@@ -12,7 +12,7 @@ namespace Discord.Commands | |||||
public int? Permissions { get; } | public int? Permissions { get; } | ||||
public string[] Args { get; } | public string[] Args { get; } | ||||
public Member Member => Message.Member; | |||||
public User Member => Message.Member; | |||||
public Channel Channel => Message.Channel; | public Channel Channel => Message.Channel; | ||||
public Server Server => Message.Channel.Server; | public Server Server => Message.Channel.Server; | ||||
@@ -8,7 +8,7 @@ namespace Discord.Commands | |||||
{ | { | ||||
private readonly DiscordClient _client; | private readonly DiscordClient _client; | ||||
private List<Command> _commands; | private List<Command> _commands; | ||||
private Func<Member, int> _getPermissions; | |||||
private Func<User, int> _getPermissions; | |||||
public IEnumerable<Command> Commands => _commands; | public IEnumerable<Command> Commands => _commands; | ||||
@@ -17,7 +17,7 @@ namespace Discord.Commands | |||||
public bool RequireCommandCharInPublic { get; set; } | public bool RequireCommandCharInPublic { get; set; } | ||||
public bool RequireCommandCharInPrivate { get; set; } | public bool RequireCommandCharInPrivate { get; set; } | ||||
public CommandsPlugin(DiscordClient client, Func<Member, int> getPermissions = null) | |||||
public CommandsPlugin(DiscordClient client, Func<User, int> getPermissions = null) | |||||
{ | { | ||||
_client = client; | _client = client; | ||||
_getPermissions = getPermissions; | _getPermissions = getPermissions; | ||||
@@ -208,6 +208,9 @@ | |||||
<Compile Include="..\Discord.Net\Helpers\AsyncCollection.cs"> | <Compile Include="..\Discord.Net\Helpers\AsyncCollection.cs"> | ||||
<Link>Helpers\AsyncCollection.cs</Link> | <Link>Helpers\AsyncCollection.cs</Link> | ||||
</Compile> | </Compile> | ||||
<Compile Include="..\Discord.Net\Helpers\BitHelper.cs"> | |||||
<Link>Helpers\BitHelper.cs</Link> | |||||
</Compile> | |||||
<Compile Include="..\Discord.Net\Helpers\EpochTime.cs"> | <Compile Include="..\Discord.Net\Helpers\EpochTime.cs"> | ||||
<Link>Helpers\EpochTime.cs</Link> | <Link>Helpers\EpochTime.cs</Link> | ||||
</Compile> | </Compile> | ||||
@@ -33,7 +33,7 @@ namespace Discord | |||||
} | } | ||||
/// <summary> Bans a user from the provided server. </summary> | /// <summary> Bans a user from the provided server. </summary> | ||||
public Task Ban(Member member) | |||||
public Task Ban(User member) | |||||
{ | { | ||||
if (member == null) throw new ArgumentNullException(nameof(member)); | if (member == null) throw new ArgumentNullException(nameof(member)); | ||||
CheckReady(); | CheckReady(); | ||||
@@ -42,7 +42,7 @@ namespace Discord | |||||
} | } | ||||
/// <summary> Unbans a user from the provided server. </summary> | /// <summary> Unbans a user from the provided server. </summary> | ||||
public async Task Unban(Member member) | |||||
public async Task Unban(User member) | |||||
{ | { | ||||
if (member == null) throw new ArgumentNullException(nameof(member)); | if (member == null) throw new ArgumentNullException(nameof(member)); | ||||
CheckReady(); | CheckReady(); | ||||
@@ -95,7 +95,7 @@ namespace Discord | |||||
} | } | ||||
/// <summary> Returns the private channel with the provided user, creating one if it does not currently exist. </summary> | /// <summary> Returns the private channel with the provided user, creating one if it does not currently exist. </summary> | ||||
public async Task<Channel> CreatePMChannel(Member member) | |||||
public async Task<Channel> CreatePMChannel(User member) | |||||
{ | { | ||||
if (member == null) throw new ArgumentNullException(nameof(member)); | if (member == null) throw new ArgumentNullException(nameof(member)); | ||||
CheckReady(); | CheckReady(); | ||||
@@ -5,36 +5,36 @@ using System.Threading.Tasks; | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
internal sealed class Members : AsyncCollection<Member> | |||||
internal sealed class Members : AsyncCollection<User> | |||||
{ | { | ||||
public Members(DiscordClient client, object writerLock) | public Members(DiscordClient client, object writerLock) | ||||
: base(client, writerLock, x => x.OnCached(), x => x.OnUncached()) { } | : base(client, writerLock, x => x.OnCached(), x => x.OnUncached()) { } | ||||
private string GetKey(string userId, string serverId) | private string GetKey(string userId, string serverId) | ||||
=> serverId + '_' + userId; | => serverId + '_' + userId; | ||||
public Member this[string userId, string serverId] | |||||
public User this[string userId, string serverId] | |||||
=> this[GetKey(userId, serverId)]; | => this[GetKey(userId, serverId)]; | ||||
public Member GetOrAdd(string userId, string serverId) | |||||
=> GetOrAdd(GetKey(userId, serverId), () => new Member(_client, userId, serverId)); | |||||
public Member TryRemove(string userId, string serverId) | |||||
public User GetOrAdd(string userId, string serverId) | |||||
=> GetOrAdd(GetKey(userId, serverId), () => new User(_client, userId, serverId)); | |||||
public User TryRemove(string userId, string serverId) | |||||
=> TryRemove(GetKey(userId, serverId)); | => TryRemove(GetKey(userId, serverId)); | ||||
} | } | ||||
public class MemberEventArgs : EventArgs | public class MemberEventArgs : EventArgs | ||||
{ | { | ||||
public Member Member { get; } | |||||
public User Member { get; } | |||||
public string UserId => Member.Id; | public string UserId => Member.Id; | ||||
public Server Server => Member.Server; | public Server Server => Member.Server; | ||||
public string ServerId => Member.ServerId; | public string ServerId => Member.ServerId; | ||||
internal MemberEventArgs(Member member) { Member = member; } | |||||
internal MemberEventArgs(User member) { Member = member; } | |||||
} | } | ||||
public class MemberChannelEventArgs : MemberEventArgs | public class MemberChannelEventArgs : MemberEventArgs | ||||
{ | { | ||||
public Channel Channel { get; } | public Channel Channel { get; } | ||||
public string ChannelId => Channel.Id; | public string ChannelId => Channel.Id; | ||||
internal MemberChannelEventArgs(Member member, Channel channel) | |||||
internal MemberChannelEventArgs(User member, Channel channel) | |||||
: base(member) | : base(member) | ||||
{ | { | ||||
Channel = channel; | Channel = channel; | ||||
@@ -44,7 +44,7 @@ namespace Discord | |||||
{ | { | ||||
public bool IsSpeaking { get; } | public bool IsSpeaking { get; } | ||||
internal MemberIsSpeakingEventArgs(Member member, Channel channel, bool isSpeaking) | |||||
internal MemberIsSpeakingEventArgs(User member, Channel channel, bool isSpeaking) | |||||
: base(member, channel) | : base(member, channel) | ||||
{ | { | ||||
IsSpeaking = isSpeaking; | IsSpeaking = isSpeaking; | ||||
@@ -54,25 +54,25 @@ namespace Discord | |||||
public partial class DiscordClient | public partial class DiscordClient | ||||
{ | { | ||||
public event EventHandler<MemberChannelEventArgs> UserIsTyping; | public event EventHandler<MemberChannelEventArgs> UserIsTyping; | ||||
private void RaiseUserIsTyping(Member member, Channel channel) | |||||
private void RaiseUserIsTyping(User member, Channel channel) | |||||
{ | { | ||||
if (UserIsTyping != null) | if (UserIsTyping != null) | ||||
RaiseEvent(nameof(UserIsTyping), () => UserIsTyping(this, new MemberChannelEventArgs(member, channel))); | RaiseEvent(nameof(UserIsTyping), () => UserIsTyping(this, new MemberChannelEventArgs(member, channel))); | ||||
} | } | ||||
public event EventHandler<MemberIsSpeakingEventArgs> UserIsSpeaking; | public event EventHandler<MemberIsSpeakingEventArgs> UserIsSpeaking; | ||||
private void RaiseUserIsSpeaking(Member member, Channel channel, bool isSpeaking) | |||||
private void RaiseUserIsSpeaking(User member, Channel channel, bool isSpeaking) | |||||
{ | { | ||||
if (UserIsSpeaking != null) | if (UserIsSpeaking != null) | ||||
RaiseEvent(nameof(UserIsSpeaking), () => UserIsSpeaking(this, new MemberIsSpeakingEventArgs(member, channel, isSpeaking))); | RaiseEvent(nameof(UserIsSpeaking), () => UserIsSpeaking(this, new MemberIsSpeakingEventArgs(member, channel, isSpeaking))); | ||||
} | } | ||||
private Member _currentUser; | |||||
private User _currentUser; | |||||
internal Members Members => _members; | internal Members Members => _members; | ||||
private readonly Members _members; | private readonly Members _members; | ||||
/// <summary> Returns the user with the specified id, along with their server-specific data, or null if none was found. </summary> | /// <summary> Returns the user with the specified id, along with their server-specific data, or null if none was found. </summary> | ||||
public Member GetMember(Server server, string userId) | |||||
public User GetMember(Server server, string userId) | |||||
{ | { | ||||
if (server == null) throw new ArgumentNullException(nameof(server)); | if (server == null) throw new ArgumentNullException(nameof(server)); | ||||
if (userId == null) throw new ArgumentNullException(nameof(userId)); | if (userId == null) throw new ArgumentNullException(nameof(userId)); | ||||
@@ -82,26 +82,26 @@ namespace Discord | |||||
} | } | ||||
/// <summary> Returns the user with the specified name and discriminator, along withtheir server-specific data, or null if they couldn't be found. </summary> | /// <summary> Returns the user with the specified name and discriminator, along withtheir server-specific data, or null if they couldn't be found. </summary> | ||||
/// <remarks> Name formats supported: Name and @Name. Search is case-insensitive. </remarks> | /// <remarks> Name formats supported: Name and @Name. Search is case-insensitive. </remarks> | ||||
public Member GetMember(Server server, string username, string discriminator) | |||||
public User GetMember(Server server, string username, string discriminator) | |||||
{ | { | ||||
if (server == null) throw new ArgumentNullException(nameof(server)); | if (server == null) throw new ArgumentNullException(nameof(server)); | ||||
if (username == null) throw new ArgumentNullException(nameof(username)); | if (username == null) throw new ArgumentNullException(nameof(username)); | ||||
if (discriminator == null) throw new ArgumentNullException(nameof(discriminator)); | if (discriminator == null) throw new ArgumentNullException(nameof(discriminator)); | ||||
CheckReady(); | CheckReady(); | ||||
Member member = FindMembers(server, username, discriminator, true).FirstOrDefault(); | |||||
User member = FindMembers(server, username, discriminator, true).FirstOrDefault(); | |||||
return _members[member?.Id, server.Id]; | return _members[member?.Id, server.Id]; | ||||
} | } | ||||
/// <summary> Returns all users in with the specified server and name, along with their server-specific data. </summary> | /// <summary> Returns all users in with the specified server and name, along with their server-specific data. </summary> | ||||
/// <remarks> Name formats supported: Name and @Name. Search is case-insensitive.</remarks> | /// <remarks> Name formats supported: Name and @Name. Search is case-insensitive.</remarks> | ||||
public IEnumerable<Member> FindMembers(Server server, string name, string discriminator = null, bool exactMatch = false) | |||||
public IEnumerable<User> FindMembers(Server server, string name, string discriminator = null, bool exactMatch = false) | |||||
{ | { | ||||
if (server == null) throw new ArgumentNullException(nameof(server)); | if (server == null) throw new ArgumentNullException(nameof(server)); | ||||
if (name == null) throw new ArgumentNullException(nameof(name)); | if (name == null) throw new ArgumentNullException(nameof(name)); | ||||
CheckReady(); | CheckReady(); | ||||
IEnumerable<Member> query; | |||||
IEnumerable<User> query; | |||||
if (!exactMatch && name.StartsWith("@")) | if (!exactMatch && name.StartsWith("@")) | ||||
{ | { | ||||
string name2 = name.Substring(1); | string name2 = name.Substring(1); | ||||
@@ -118,7 +118,7 @@ namespace Discord | |||||
return query; | return query; | ||||
} | } | ||||
public Task EditMember(Member member, bool? mute = null, bool? deaf = null, IEnumerable<Role> roles = null) | |||||
public Task EditMember(User member, bool? mute = null, bool? deaf = null, IEnumerable<Role> roles = null) | |||||
{ | { | ||||
if (member == null) throw new ArgumentNullException(nameof(member)); | if (member == null) throw new ArgumentNullException(nameof(member)); | ||||
CheckReady(); | CheckReady(); | ||||
@@ -20,7 +20,7 @@ namespace Discord | |||||
public class MessageEventArgs : EventArgs | public class MessageEventArgs : EventArgs | ||||
{ | { | ||||
public Message Message { get; } | public Message Message { get; } | ||||
public Member Member => Message.Member; | |||||
public User Member => Message.Member; | |||||
public Channel Channel => Message.Channel; | public Channel Channel => Message.Channel; | ||||
public Server Server => Message.Server; | public Server Server => Message.Server; | ||||
@@ -87,7 +87,7 @@ namespace Discord | |||||
return SendMessage(channel, text, false); | return SendMessage(channel, text, false); | ||||
} | } | ||||
/// <summary> Sends a private message to the provided user. </summary> | /// <summary> Sends a private message to the provided user. </summary> | ||||
public async Task<Message> SendPrivateMessage(Member member, string text) | |||||
public async Task<Message> SendPrivateMessage(User member, string text) | |||||
{ | { | ||||
if (member == null) throw new ArgumentNullException(nameof(member)); | if (member == null) throw new ArgumentNullException(nameof(member)); | ||||
if (text == null) throw new ArgumentNullException(nameof(text)); | if (text == null) throw new ArgumentNullException(nameof(text)); | ||||
@@ -103,8 +103,11 @@ namespace Discord | |||||
if (Config.UseMessageQueue) | if (Config.UseMessageQueue) | ||||
{ | { | ||||
var nonce = GenerateNonce(); | var nonce = GenerateNonce(); | ||||
msg = _messages.GetOrAdd("nonce_" + nonce, channel.Id, _userId); | |||||
var currentUser = msg.Member; | |||||
if (_messages != null) | |||||
msg = _messages.GetOrAdd("nonce_" + nonce, channel.Id, _userId); | |||||
else | |||||
msg = new Message(this, "nonce_" + nonce, channel.Id, _userId); | |||||
var currentUser = msg.Member; | |||||
msg.Update(new MessageInfo | msg.Update(new MessageInfo | ||||
{ | { | ||||
Content = text, | Content = text, | ||||
@@ -121,7 +124,10 @@ namespace Discord | |||||
else | else | ||||
{ | { | ||||
var model = await _api.SendMessage(channel.Id, text, userIds, null, isTextToSpeech).ConfigureAwait(false); | var model = await _api.SendMessage(channel.Id, text, userIds, null, isTextToSpeech).ConfigureAwait(false); | ||||
msg = _messages.GetOrAdd(model.Id, channel.Id, model.Author.Id); | |||||
if (_messages != null) | |||||
msg = _messages.GetOrAdd(model.Id, channel.Id, model.Author.Id); | |||||
else | |||||
msg = new Message(this, model.Id, channel.Id, _userId); | |||||
msg.Update(model); | msg.Update(model); | ||||
RaiseMessageSent(msg); | RaiseMessageSent(msg); | ||||
} | } | ||||
@@ -197,27 +203,29 @@ namespace Discord | |||||
var msgs = await _api.GetMessages(channel.Id, count).ConfigureAwait(false); | var msgs = await _api.GetMessages(channel.Id, count).ConfigureAwait(false); | ||||
return msgs.Select(x => | return msgs.Select(x => | ||||
{ | { | ||||
Message msg; | |||||
if (cache) | |||||
msg = _messages.GetOrAdd(x.Id, x.ChannelId, x.Author.Id); | |||||
else | |||||
msg = _messages[x.Id] ?? new Message(this, x.Id, x.ChannelId, x.Author.Id); | |||||
if (msg != null) | |||||
Message msg = null; | |||||
if (_messages != null) | |||||
{ | { | ||||
msg.Update(x); | |||||
if (Config.TrackActivity) | |||||
if (cache && _messages != null) | |||||
msg = _messages.GetOrAdd(x.Id, x.ChannelId, x.Author.Id); | |||||
else | |||||
msg = _messages[x.Id]; | |||||
} | |||||
if (msg == null) | |||||
msg = new Message(this, x.Id, x.ChannelId, x.Author.Id); | |||||
msg.Update(x); | |||||
if (Config.TrackActivity) | |||||
{ | |||||
if (!channel.IsPrivate) | |||||
{ | { | ||||
if (!channel.IsPrivate) | |||||
{ | |||||
var member = msg.Member; | |||||
if (member != null) | |||||
member.UpdateActivity(msg.EditedTimestamp ?? msg.Timestamp); | |||||
} | |||||
var member = msg.Member; | |||||
if (member != null) | |||||
member.UpdateActivity(msg.EditedTimestamp ?? msg.Timestamp); | |||||
} | } | ||||
} | } | ||||
return msg; | return msg; | ||||
}) | }) | ||||
.ToArray(); | |||||
.ToArray(); | |||||
} | } | ||||
catch (HttpException) { } //Bad Permissions? | catch (HttpException) { } //Bad Permissions? | ||||
} | } | ||||
@@ -7,7 +7,7 @@ namespace Discord | |||||
{ | { | ||||
public partial class DiscordClient | public partial class DiscordClient | ||||
{ | { | ||||
public Task SetChannelUserPermissions(Channel channel, Member member, ChannelPermissions allow = null, ChannelPermissions deny = null) | |||||
public Task SetChannelUserPermissions(Channel channel, User member, ChannelPermissions allow = null, ChannelPermissions deny = null) | |||||
{ | { | ||||
if (channel == null) throw new ArgumentNullException(nameof(channel)); | if (channel == null) throw new ArgumentNullException(nameof(channel)); | ||||
if (member == null) throw new ArgumentNullException(nameof(member)); | if (member == null) throw new ArgumentNullException(nameof(member)); | ||||
@@ -15,7 +15,7 @@ namespace Discord | |||||
return SetChannelPermissions(channel, member?.Id, PermissionTarget.Member, allow, deny); | return SetChannelPermissions(channel, member?.Id, PermissionTarget.Member, allow, deny); | ||||
} | } | ||||
public Task SetChannelUserPermissions(Channel channel, Member member, DualChannelPermissions permissions = null) | |||||
public Task SetChannelUserPermissions(Channel channel, User member, DualChannelPermissions permissions = null) | |||||
{ | { | ||||
if (channel == null) throw new ArgumentNullException(nameof(channel)); | if (channel == null) throw new ArgumentNullException(nameof(channel)); | ||||
if (member == null) throw new ArgumentNullException(nameof(member)); | if (member == null) throw new ArgumentNullException(nameof(member)); | ||||
@@ -56,11 +56,11 @@ namespace Discord | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
var oldPerms = channel._permissionOverwrites; | |||||
var oldPerms = channel.PermissionOverwrites.ToArray(); | |||||
var newPerms = new Channel.PermissionOverwrite[oldPerms.Length + 1]; | var newPerms = new Channel.PermissionOverwrite[oldPerms.Length + 1]; | ||||
Array.Copy(oldPerms, newPerms, oldPerms.Length); | Array.Copy(oldPerms, newPerms, oldPerms.Length); | ||||
newPerms[oldPerms.Length] = new Channel.PermissionOverwrite(targetType, targetId, allowValue, denyValue); | newPerms[oldPerms.Length] = new Channel.PermissionOverwrite(targetType, targetId, allowValue, denyValue); | ||||
channel._permissionOverwrites = newPerms; | |||||
channel.PermissionOverwrites = newPerms; | |||||
} | } | ||||
changed = true; | changed = true; | ||||
} | } | ||||
@@ -71,7 +71,7 @@ namespace Discord | |||||
await _api.DeleteChannelPermissions(channel.Id, targetId); | await _api.DeleteChannelPermissions(channel.Id, targetId); | ||||
if (perms != null) | if (perms != null) | ||||
{ | { | ||||
channel._permissionOverwrites = channel.PermissionOverwrites.Where(x => x.TargetType != targetType || x.TargetId != targetId).ToArray(); | |||||
channel.PermissionOverwrites = channel.PermissionOverwrites.Where(x => x.TargetType != targetType || x.TargetId != targetId).ToArray(); | |||||
changed = true; | changed = true; | ||||
} | } | ||||
} | } | ||||
@@ -87,7 +87,7 @@ namespace Discord | |||||
} | } | ||||
} | } | ||||
public Task RemoveChannelUserPermissions(Channel channel, Member member) | |||||
public Task RemoveChannelUserPermissions(Channel channel, User member) | |||||
{ | { | ||||
if (channel == null) throw new ArgumentNullException(nameof(channel)); | if (channel == null) throw new ArgumentNullException(nameof(channel)); | ||||
if (member == null) throw new ArgumentNullException(nameof(member)); | if (member == null) throw new ArgumentNullException(nameof(member)); | ||||
@@ -17,13 +17,13 @@ namespace Discord | |||||
public partial class DiscordClient | public partial class DiscordClient | ||||
{ | { | ||||
public event EventHandler<MemberEventArgs> UserAdded; | public event EventHandler<MemberEventArgs> UserAdded; | ||||
private void RaiseUserAdded(Member member) | |||||
private void RaiseUserAdded(User member) | |||||
{ | { | ||||
if (UserAdded != null) | if (UserAdded != null) | ||||
RaiseEvent(nameof(UserAdded), () => UserAdded(this, new MemberEventArgs(member))); | RaiseEvent(nameof(UserAdded), () => UserAdded(this, new MemberEventArgs(member))); | ||||
} | } | ||||
public event EventHandler<MemberEventArgs> UserRemoved; | public event EventHandler<MemberEventArgs> UserRemoved; | ||||
private void RaiseUserRemoved(Member member) | |||||
private void RaiseUserRemoved(User member) | |||||
{ | { | ||||
if (UserRemoved != null) | if (UserRemoved != null) | ||||
RaiseEvent(nameof(UserRemoved), () => UserRemoved(this, new MemberEventArgs(member))); | RaiseEvent(nameof(UserRemoved), () => UserRemoved(this, new MemberEventArgs(member))); | ||||
@@ -35,19 +35,19 @@ namespace Discord | |||||
RaiseEvent(nameof(ProfileUpdated), () => ProfileUpdated(this, EventArgs.Empty)); | RaiseEvent(nameof(ProfileUpdated), () => ProfileUpdated(this, EventArgs.Empty)); | ||||
} | } | ||||
public event EventHandler<MemberEventArgs> MemberUpdated; | public event EventHandler<MemberEventArgs> MemberUpdated; | ||||
private void RaiseMemberUpdated(Member member) | |||||
private void RaiseMemberUpdated(User member) | |||||
{ | { | ||||
if (MemberUpdated != null) | if (MemberUpdated != null) | ||||
RaiseEvent(nameof(MemberUpdated), () => MemberUpdated(this, new MemberEventArgs(member))); | RaiseEvent(nameof(MemberUpdated), () => MemberUpdated(this, new MemberEventArgs(member))); | ||||
} | } | ||||
public event EventHandler<MemberEventArgs> UserPresenceUpdated; | public event EventHandler<MemberEventArgs> UserPresenceUpdated; | ||||
private void RaiseUserPresenceUpdated(Member member) | |||||
private void RaiseUserPresenceUpdated(User member) | |||||
{ | { | ||||
if (UserPresenceUpdated != null) | if (UserPresenceUpdated != null) | ||||
RaiseEvent(nameof(UserPresenceUpdated), () => UserPresenceUpdated(this, new MemberEventArgs(member))); | RaiseEvent(nameof(UserPresenceUpdated), () => UserPresenceUpdated(this, new MemberEventArgs(member))); | ||||
} | } | ||||
public event EventHandler<MemberEventArgs> UserVoiceStateUpdated; | public event EventHandler<MemberEventArgs> UserVoiceStateUpdated; | ||||
private void RaiseUserVoiceStateUpdated(Member member) | |||||
private void RaiseUserVoiceStateUpdated(User member) | |||||
{ | { | ||||
if (UserVoiceStateUpdated != null) | if (UserVoiceStateUpdated != null) | ||||
RaiseEvent(nameof(UserVoiceStateUpdated), () => UserVoiceStateUpdated(this, new MemberEventArgs(member))); | RaiseEvent(nameof(UserVoiceStateUpdated), () => UserVoiceStateUpdated(this, new MemberEventArgs(member))); | ||||
@@ -28,7 +28,7 @@ namespace Discord | |||||
public DiscordAPIClient API => _api; | public DiscordAPIClient API => _api; | ||||
/// <summary> Returns the current logged-in user. </summary> | /// <summary> Returns the current logged-in user. </summary> | ||||
public Member CurrentUser => _currentUser; | |||||
public User CurrentUser => _currentUser; | |||||
/// <summary> Initializes a new instance of the DiscordClient class. </summary> | /// <summary> Initializes a new instance of the DiscordClient class. </summary> | ||||
public DiscordClient(DiscordClientConfig config = null) | public DiscordClient(DiscordClientConfig config = null) | ||||
@@ -495,7 +495,12 @@ namespace Discord | |||||
} | } | ||||
if (msg == null) | if (msg == null) | ||||
msg = _messages.GetOrAdd(data.Id, data.ChannelId, data.Author.Id); | |||||
{ | |||||
if (_messages != null) | |||||
msg = _messages.GetOrAdd(data.Id, data.ChannelId, data.Author.Id); | |||||
else | |||||
msg = new Message(this, data.Id, data.ChannelId, data.Author.Id); | |||||
} | |||||
msg.Update(data); | msg.Update(data); | ||||
if (Config.TrackActivity) | if (Config.TrackActivity) | ||||
{ | { | ||||
@@ -5,6 +5,9 @@ | |||||
/// <summary> Gets or sets the time (in milliseconds) to wait when the message queue is empty before checking again. </summary> | /// <summary> Gets or sets the time (in milliseconds) to wait when the message queue is empty before checking again. </summary> | ||||
public int MessageQueueInterval { get { return _messageQueueInterval; } set { SetValue(ref _messageQueueInterval, value); } } | public int MessageQueueInterval { get { return _messageQueueInterval; } set { SetValue(ref _messageQueueInterval, value); } } | ||||
private int _messageQueueInterval = 100; | private int _messageQueueInterval = 100; | ||||
/// <summary> Gets or sets the number of messages per channel that should be kept in cache. Setting this to zero disables the message cache entirely. </summary> | |||||
public int MessageCacheLength { get { return _messageCacheLength; } set { SetValue(ref _messageCacheLength, value); } } | |||||
private int _messageCacheLength = 100; | |||||
//Experimental Features | //Experimental Features | ||||
/// <summary> (Experimental) Enables the client to be simultaneously connected to multiple channels at once (Discord still limits you to one channel per server). </summary> | /// <summary> (Experimental) Enables the client to be simultaneously connected to multiple channels at once (Discord still limits you to one channel per server). </summary> | ||||
@@ -0,0 +1,20 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
namespace Discord | |||||
{ | |||||
internal static class BitHelper | |||||
{ | |||||
public static bool GetBit(uint value, int pos) => ((value >> (byte)pos) & 1U) == 1; | |||||
public static void SetBit(ref uint value, int pos, bool bitValue) | |||||
{ | |||||
if (bitValue) | |||||
value |= (1U << pos); | |||||
else | |||||
value &= ~(1U << pos); | |||||
} | |||||
} | |||||
} |
@@ -10,7 +10,7 @@ namespace Discord | |||||
private static readonly Regex _channelRegex = new Regex(@"<#(\d+?)>", RegexOptions.Compiled); | private static readonly Regex _channelRegex = new Regex(@"<#(\d+?)>", RegexOptions.Compiled); | ||||
/// <summary> Returns the string used to create a user mention. </summary> | /// <summary> Returns the string used to create a user mention. </summary> | ||||
public static string User(Member member) | |||||
public static string User(User member) | |||||
=> $"<@{member.Id}>"; | => $"<@{member.Id}>"; | ||||
/// <summary> Returns the string used to create a channel mention. </summary> | /// <summary> Returns the string used to create a channel mention. </summary> | ||||
public static string Channel(Channel channel) | public static string Channel(Channel channel) | ||||
@@ -1,6 +1,5 @@ | |||||
using Discord.API; | using Discord.API; | ||||
using Newtonsoft.Json; | using Newtonsoft.Json; | ||||
using System; | |||||
using System.Collections.Concurrent; | using System.Collections.Concurrent; | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.Linq; | using System.Linq; | ||||
@@ -26,14 +25,7 @@ namespace Discord | |||||
Deny.Lock(); | Deny.Lock(); | ||||
} | } | ||||
} | } | ||||
private readonly ConcurrentDictionary<string, bool> _messages; | |||||
private bool _areMembersStale; | |||||
private readonly string _serverId, _recipientId; | |||||
private Server _server; | |||||
private Member _recipient; | |||||
/// <summary> Returns the name of this channel. </summary> | /// <summary> Returns the name of this channel. </summary> | ||||
public string Name { get; private set; } | public string Name { get; private set; } | ||||
/// <summary> Returns the topic associated with this channel. </summary> | /// <summary> Returns the topic associated with this channel. </summary> | ||||
@@ -47,41 +39,40 @@ namespace Discord | |||||
/// <summary> Returns the server containing this channel. </summary> | /// <summary> Returns the server containing this channel. </summary> | ||||
[JsonIgnore] | [JsonIgnore] | ||||
public Server Server => _client.Servers[_serverId]; | |||||
public Server Server { get; private set; } | |||||
private readonly string _serverId; | |||||
/// For private chats, returns the target user, otherwise null. | /// For private chats, returns the target user, otherwise null. | ||||
[JsonIgnore] | [JsonIgnore] | ||||
public Member Recipient => _client.Members[_recipientId, _serverId]; | |||||
/// <summary> Returns a collection of the IDs of all users with read access to this channel. </summary> | |||||
public IEnumerable<string> UserIds | |||||
public User Recipient { get; private set; } | |||||
private readonly string _recipientId; | |||||
/// <summary> Returns a collection of all users with read access to this channel. </summary> | |||||
[JsonIgnore] | |||||
public IEnumerable<User> Members | |||||
{ | { | ||||
get | get | ||||
{ | { | ||||
if (!_areMembersStale) | if (!_areMembersStale) | ||||
return _userIds; | |||||
_userIds = Server.Members.Where(x => x.GetPermissions(this)?.ReadMessages ?? false).Select(x => x.Id).ToArray(); | |||||
return _members; | |||||
_members = Server.Members.Where(x => x.GetPermissions(this)?.ReadMessages ?? false).ToArray(); | |||||
_areMembersStale = false; | _areMembersStale = false; | ||||
return _userIds; | |||||
} | |||||
return _members; | |||||
} | |||||
} | } | ||||
private string[] _userIds; | |||||
/// <summary> Returns a collection of all users with read access to this channel. </summary> | |||||
[JsonIgnore] | |||||
public IEnumerable<Member> Members => UserIds.Select(x => _client.Members[x, _serverId]); | |||||
private User[] _members; | |||||
private bool _areMembersStale; | |||||
/// <summary> Returns a collection of the ids of all messages the client has seen posted in this channel. This collection does not guarantee any ordering. </summary> | |||||
[JsonIgnore] | |||||
public IEnumerable<string> MessageIds => _messages.Select(x => x.Key); | |||||
/// <summary> Returns a collection of all messages the client has seen posted in this channel. This collection does not guarantee any ordering. </summary> | /// <summary> Returns a collection of all messages the client has seen posted in this channel. This collection does not guarantee any ordering. </summary> | ||||
[JsonIgnore] | [JsonIgnore] | ||||
public IEnumerable<Message> Messages => _messages.Select(x => _client.Messages[x.Key]); | |||||
public IEnumerable<Message> Messages => _messages.Values; | |||||
private readonly ConcurrentDictionary<string, Message> _messages; | |||||
/// <summary> Returns a collection of all custom permissions used for this channel. </summary> | /// <summary> Returns a collection of all custom permissions used for this channel. </summary> | ||||
private static readonly PermissionOverwrite[] _initialPermissionsOverwrites = new PermissionOverwrite[0]; | private static readonly PermissionOverwrite[] _initialPermissionsOverwrites = new PermissionOverwrite[0]; | ||||
internal PermissionOverwrite[] _permissionOverwrites; | |||||
public IEnumerable<PermissionOverwrite> PermissionOverwrites => _permissionOverwrites; | |||||
private PermissionOverwrite[] _permissionOverwrites; | |||||
public IEnumerable<PermissionOverwrite> PermissionOverwrites { get { return _permissionOverwrites; } internal set { _permissionOverwrites = value.ToArray(); } } | |||||
internal Channel(DiscordClient client, string id, string serverId, string recipientId) | internal Channel(DiscordClient client, string id, string serverId, string recipientId) | ||||
: base(client, id) | : base(client, id) | ||||
@@ -92,31 +83,35 @@ namespace Discord | |||||
_areMembersStale = true; | _areMembersStale = true; | ||||
//Local Cache | //Local Cache | ||||
_messages = new ConcurrentDictionary<string, bool>(); | |||||
_messages = new ConcurrentDictionary<string, Message>(); | |||||
} | } | ||||
internal override void OnCached() | internal override void OnCached() | ||||
{ | { | ||||
if (IsPrivate) | if (IsPrivate) | ||||
{ | { | ||||
_recipient = _client.Members[_recipientId, _serverId]; | |||||
Name = "@" + _recipient.Name; | |||||
var recipient = _client.Members[_recipientId, _serverId]; | |||||
Name = "@" + recipient.Name; | |||||
Recipient = recipient; | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
_server = _client.Servers[_serverId]; | |||||
_server.AddChannel(this); | |||||
var server = _client.Servers[_serverId]; | |||||
server.AddChannel(this); | |||||
Server = server; | |||||
} | } | ||||
} | } | ||||
internal override void OnUncached() | internal override void OnUncached() | ||||
{ | { | ||||
if (_server != null) | |||||
_server.RemoveChannel(this); | |||||
_server = null; | |||||
if (_recipient != null) | |||||
_recipient.GlobalUser.PrivateChannel = null; | |||||
_recipient = null; | |||||
var server = Server; | |||||
if (server != null) | |||||
server.RemoveChannel(this); | |||||
Server = null; | |||||
var recipient = Recipient; | |||||
if (recipient != null) | |||||
recipient.GlobalUser.PrivateChannel = null; | |||||
Recipient = recipient; | |||||
} | } | ||||
internal void Update(ChannelReference model) | internal void Update(ChannelReference model) | ||||
@@ -146,15 +141,21 @@ namespace Discord | |||||
public override string ToString() => Name; | public override string ToString() => Name; | ||||
internal void AddMessage(string messageId) | |||||
{ | |||||
_messages.TryAdd(messageId, true); | |||||
} | |||||
internal bool RemoveMessage(string messageId) | |||||
internal void AddMessage(Message message) | |||||
{ | { | ||||
bool ignored; | |||||
return _messages.TryRemove(messageId, out ignored); | |||||
var cacheLength = _client.Config.MessageCacheLength; | |||||
if (cacheLength > 0) | |||||
{ | |||||
while (_messages.Count > cacheLength - 1) | |||||
{ | |||||
var oldest = _messages.Select(x => x.Value.Id).OrderBy(x => x).FirstOrDefault(); | |||||
if (oldest != null) | |||||
_client.Messages.TryRemove(oldest); | |||||
} | |||||
_messages.TryAdd(message.Id, message); | |||||
} | |||||
} | } | ||||
internal void RemoveMessage(Message message) => _messages.TryRemove(message.Id, out message); | |||||
internal void InvalidMembersCache() | internal void InvalidMembersCache() | ||||
{ | { | ||||
@@ -164,14 +165,14 @@ namespace Discord | |||||
{ | { | ||||
_areMembersStale = true; | _areMembersStale = true; | ||||
foreach (var member in Members) | foreach (var member in Members) | ||||
member.UpdatePermissions(this); | |||||
member.UpdateChannelPermissions(this); | |||||
} | } | ||||
internal void InvalidatePermissionsCache(string userId) | internal void InvalidatePermissionsCache(string userId) | ||||
{ | { | ||||
_areMembersStale = true; | _areMembersStale = true; | ||||
var member = _client.Members[userId, _serverId]; | var member = _client.Members[userId, _serverId]; | ||||
if (member != null) | if (member != null) | ||||
member.UpdatePermissions(this); | |||||
member.UpdateChannelPermissions(this); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -27,7 +27,7 @@ namespace Discord | |||||
/// <summary> Returns a collection of all server-specific data for every server this user is a member of. </summary> | /// <summary> Returns a collection of all server-specific data for every server this user is a member of. </summary> | ||||
[JsonIgnore] | [JsonIgnore] | ||||
public IEnumerable<Member> Memberships => _servers.Select(x => _client.Members[Id, x.Key]); | |||||
public IEnumerable<User> Memberships => _servers.Select(x => _client.Members[Id, x.Key]); | |||||
/// <summary> Returns a collection of all servers this user is a member of. </summary> | /// <summary> Returns a collection of all servers this user is a member of. </summary> | ||||
[JsonIgnore] | [JsonIgnore] | ||||
public IEnumerable<Server> Servers => _servers.Select(x => _client.Servers[x.Key]); | public IEnumerable<Server> Servers => _servers.Select(x => _client.Servers[x.Key]); | ||||
@@ -27,7 +27,7 @@ namespace Discord | |||||
/// <summary> Returns the user that created this invite. </summary> | /// <summary> Returns the user that created this invite. </summary> | ||||
[JsonIgnore] | [JsonIgnore] | ||||
public Member Inviter => _client.Members[_inviterId, _serverId]; | |||||
public User Inviter => _client.Members[_inviterId, _serverId]; | |||||
/// <summary> Returns the server this invite is to. </summary> | /// <summary> Returns the server this invite is to. </summary> | ||||
[JsonIgnore] | [JsonIgnore] | ||||
@@ -129,7 +129,7 @@ namespace Discord | |||||
public string[] MentionIds { get; private set; } | public string[] MentionIds { get; private set; } | ||||
/// <summary> Returns a collection of all users mentioned in this message. </summary> | /// <summary> Returns a collection of all users mentioned in this message. </summary> | ||||
[JsonIgnore] | [JsonIgnore] | ||||
public IEnumerable<Member> Mentions { get; internal set; } | |||||
public IEnumerable<User> Mentions { get; internal set; } | |||||
/// <summary> Returns the server containing the channel this message was sent to. </summary> | /// <summary> Returns the server containing the channel this message was sent to. </summary> | ||||
[JsonIgnore] | [JsonIgnore] | ||||
@@ -144,7 +144,7 @@ namespace Discord | |||||
public string UserId { get; } | public string UserId { get; } | ||||
/// <summary> Returns the author of this message. </summary> | /// <summary> Returns the author of this message. </summary> | ||||
[JsonIgnore] | [JsonIgnore] | ||||
public Member Member => _client.Members[_userId, Channel.Server.Id]; | |||||
public User Member => _client.Members[_userId, Channel.Server.Id]; | |||||
internal Message(DiscordClient client, string id, string channelId, string userId) | internal Message(DiscordClient client, string id, string channelId, string userId) | ||||
: base(client, id) | : base(client, id) | ||||
@@ -158,14 +158,14 @@ namespace Discord | |||||
internal override void OnCached() | internal override void OnCached() | ||||
{ | { | ||||
var channel = _client.Channels[_channelId]; | var channel = _client.Channels[_channelId]; | ||||
channel.AddMessage(Id); | |||||
channel.AddMessage(this); | |||||
Channel = channel; | Channel = channel; | ||||
} | } | ||||
internal override void OnUncached() | internal override void OnUncached() | ||||
{ | { | ||||
var channel = Channel; | var channel = Channel; | ||||
if (channel != null) | if (channel != null) | ||||
channel.RemoveMessage(Id); | |||||
channel.RemoveMessage(this); | |||||
} | } | ||||
internal void Update(MessageInfo model) | internal void Update(MessageInfo model) | ||||
@@ -127,15 +127,9 @@ namespace Discord | |||||
_rawValue = rawValue; | _rawValue = rawValue; | ||||
} | } | ||||
internal bool GetBit(PermissionsBits pos) => ((_rawValue >> (byte)pos) & 1U) == 1; | |||||
internal bool GetBit(PermissionsBits pos) => BitHelper.GetBit(_rawValue, (int)pos); | |||||
internal void SetBit(PermissionsBits pos, bool value) { CheckLock(); SetBitInternal((byte)pos, value); } | internal void SetBit(PermissionsBits pos, bool value) { CheckLock(); SetBitInternal((byte)pos, value); } | ||||
internal void SetBitInternal(int pos, bool value) | |||||
{ | |||||
if (value) | |||||
_rawValue |= (1U << pos); | |||||
else | |||||
_rawValue &= ~(1U << pos); | |||||
} | |||||
internal void SetBitInternal(int pos, bool value) => BitHelper.SetBit(ref _rawValue, pos, value); | |||||
internal void Lock() => _isLocked = true; | internal void Lock() => _isLocked = true; | ||||
protected void CheckLock() | protected void CheckLock() | ||||
@@ -31,7 +31,7 @@ namespace Discord | |||||
public bool IsEveryone => Id == _serverId; | public bool IsEveryone => Id == _serverId; | ||||
/// <summary> Returns a list of all members in this role. </summary> | /// <summary> Returns a list of all members in this role. </summary> | ||||
[JsonIgnore] | [JsonIgnore] | ||||
public IEnumerable<Member> Members => IsEveryone ? Server.Members : Server.Members.Where(x => x.HasRole(this)); | |||||
public IEnumerable<User> Members => IsEveryone ? Server.Members : Server.Members.Where(x => x.HasRole(this)); | |||||
internal Role(DiscordClient client, string id, string serverId) | internal Role(DiscordClient client, string id, string serverId) | ||||
: base(client, id) | : base(client, id) | ||||
@@ -75,7 +75,7 @@ namespace Discord | |||||
Permissions.SetRawValueInternal(model.Permissions.Value); | Permissions.SetRawValueInternal(model.Permissions.Value); | ||||
foreach (var member in Members) | foreach (var member in Members) | ||||
member.UpdatePermissions(); | |||||
member.UpdateServerPermissions(); | |||||
} | } | ||||
public override string ToString() => Name; | public override string ToString() => Name; | ||||
@@ -11,7 +11,7 @@ namespace Discord | |||||
{ | { | ||||
private readonly ConcurrentDictionary<string, bool> _bans; | private readonly ConcurrentDictionary<string, bool> _bans; | ||||
private readonly ConcurrentDictionary<string, Channel> _channels; | private readonly ConcurrentDictionary<string, Channel> _channels; | ||||
private readonly ConcurrentDictionary<string, Member> _members; | |||||
private readonly ConcurrentDictionary<string, User> _members; | |||||
private readonly ConcurrentDictionary<string, Role> _roles; | private readonly ConcurrentDictionary<string, Role> _roles; | ||||
private readonly ConcurrentDictionary<string, Invite> _invites; | private readonly ConcurrentDictionary<string, Invite> _invites; | ||||
@@ -20,7 +20,7 @@ namespace Discord | |||||
/// <summary> Returns the name of this channel. </summary> | /// <summary> Returns the name of this channel. </summary> | ||||
public string Name { get; private set; } | public string Name { get; private set; } | ||||
/// <summary> Returns the current logged-in user's data for this server. </summary> | /// <summary> Returns the current logged-in user's data for this server. </summary> | ||||
public Member CurrentMember { get; internal set; } | |||||
public User CurrentMember { get; internal set; } | |||||
/// <summary> Returns true if this is a virtual server used by Discord.Net and not a real Discord server. </summary> | /// <summary> Returns true if this is a virtual server used by Discord.Net and not a real Discord server. </summary> | ||||
public bool IsVirtual { get; internal set; } | public bool IsVirtual { get; internal set; } | ||||
@@ -37,7 +37,7 @@ namespace Discord | |||||
public bool IsOwner => _client.CurrentUserId == _ownerId; | public bool IsOwner => _client.CurrentUserId == _ownerId; | ||||
/// <summary> Returns the user that first created this server. </summary> | /// <summary> Returns the user that first created this server. </summary> | ||||
[JsonIgnore] | [JsonIgnore] | ||||
public Member Owner { get; private set; } | |||||
public User Owner { get; private set; } | |||||
/// <summary> Returns the id of the AFK voice channel for this server (see AFKTimeout). </summary> | /// <summary> Returns the id of the AFK voice channel for this server (see AFKTimeout). </summary> | ||||
public string AFKChannelId { get; private set; } | public string AFKChannelId { get; private set; } | ||||
@@ -71,7 +71,7 @@ namespace Discord | |||||
/// <summary> Returns a collection of all users within this server with their server-specific data. </summary> | /// <summary> Returns a collection of all users within this server with their server-specific data. </summary> | ||||
[JsonIgnore] | [JsonIgnore] | ||||
public IEnumerable<Member> Members => _members.Select(x => _client.Members[x.Key, Id]); | |||||
public IEnumerable<User> Members => _members.Select(x => _client.Members[x.Key, Id]); | |||||
/// <summary> Return the id of the role representing all users in a server. </summary> | /// <summary> Return the id of the role representing all users in a server. </summary> | ||||
public string EveryoneRoleId => Id; | public string EveryoneRoleId => Id; | ||||
@@ -87,7 +87,7 @@ namespace Discord | |||||
{ | { | ||||
//Global Cache | //Global Cache | ||||
_channels = new ConcurrentDictionary<string, Channel>(); | _channels = new ConcurrentDictionary<string, Channel>(); | ||||
_members = new ConcurrentDictionary<string, Member>(); | |||||
_members = new ConcurrentDictionary<string, User>(); | |||||
_roles = new ConcurrentDictionary<string, Role>(); | _roles = new ConcurrentDictionary<string, Role>(); | ||||
//Local Cache | //Local Cache | ||||
@@ -207,7 +207,7 @@ namespace Discord | |||||
internal void AddInvite(Invite invite) => _invites.TryAdd(invite.Id, invite); | internal void AddInvite(Invite invite) => _invites.TryAdd(invite.Id, invite); | ||||
internal void RemoveInvite(Invite invite) => _invites.TryRemove(invite.Id, out invite); | internal void RemoveInvite(Invite invite) => _invites.TryRemove(invite.Id, out invite); | ||||
internal void AddMember(Member member) | |||||
internal void AddMember(User member) | |||||
{ | { | ||||
_members.TryAdd(member.Id, member); | _members.TryAdd(member.Id, member); | ||||
foreach (var channel in Channels) | foreach (var channel in Channels) | ||||
@@ -216,7 +216,7 @@ namespace Discord | |||||
channel.InvalidatePermissionsCache(member.Id); | channel.InvalidatePermissionsCache(member.Id); | ||||
} | } | ||||
} | } | ||||
internal void RemoveMember(Member member) | |||||
internal void RemoveMember(User member) | |||||
{ | { | ||||
foreach (var channel in Channels) | foreach (var channel in Channels) | ||||
{ | { | ||||
@@ -225,7 +225,7 @@ namespace Discord | |||||
} | } | ||||
_members.TryRemove(member.Id, out member); | _members.TryRemove(member.Id, out member); | ||||
} | } | ||||
internal void HasMember(Member user) => _members.ContainsKey(user.Id); | |||||
internal void HasMember(User user) => _members.ContainsKey(user.Id); | |||||
internal void AddRole(Role role) => _roles.TryAdd(role.Id, role); | internal void AddRole(Role role) => _roles.TryAdd(role.Id, role); | ||||
internal void RemoveRole(Role role) => _roles.TryRemove(role.Id, out role); | internal void RemoveRole(Role role) => _roles.TryRemove(role.Id, out role); | ||||
@@ -7,13 +7,14 @@ using System.Linq; | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
public class Member : CachedObject | |||||
public class User : CachedObject | |||||
{ | { | ||||
private static readonly string[] _initialRoleIds = new string[0]; | private static readonly string[] _initialRoleIds = new string[0]; | ||||
private ConcurrentDictionary<string, Channel> _channels; | private ConcurrentDictionary<string, Channel> _channels; | ||||
private ConcurrentDictionary<string, ChannelPermissions> _permissions; | private ConcurrentDictionary<string, ChannelPermissions> _permissions; | ||||
private bool _hasRef; | |||||
private ServerPermissions _serverPermissions; | |||||
private bool _hasRef; | |||||
private string[] _roleIds; | private string[] _roleIds; | ||||
/// <summary> Returns the name of this user on this server. </summary> | /// <summary> Returns the name of this user on this server. </summary> | ||||
@@ -65,9 +66,9 @@ namespace Discord | |||||
public IEnumerable<Message> Messages => _client.Messages.Where(x => x.UserId == Id && x.Server.Id == ServerId); | public IEnumerable<Message> Messages => _client.Messages.Where(x => x.UserId == Id && x.Server.Id == ServerId); | ||||
/// <summary> Returns a collection of all channels this user is a member of. </summary> | /// <summary> Returns a collection of all channels this user is a member of. </summary> | ||||
[JsonIgnore] | [JsonIgnore] | ||||
public IEnumerable<Channel> Channels => _client.Channels.Where(x => x.Server.Id == ServerId && x.UserIds.Contains(Id)); | |||||
public IEnumerable<Channel> Channels => _client.Channels.Where(x => x.Server.Id == ServerId && x.Members == this); | |||||
internal Member(DiscordClient client, string id, string serverId) | |||||
internal User(DiscordClient client, string id, string serverId) | |||||
: base(client, id) | : base(client, id) | ||||
{ | { | ||||
ServerId = serverId; | ServerId = serverId; | ||||
@@ -75,7 +76,8 @@ namespace Discord | |||||
_roleIds = _initialRoleIds; | _roleIds = _initialRoleIds; | ||||
_channels = new ConcurrentDictionary<string, Channel>(); | _channels = new ConcurrentDictionary<string, Channel>(); | ||||
_permissions = new ConcurrentDictionary<string, ChannelPermissions>(); | _permissions = new ConcurrentDictionary<string, ChannelPermissions>(); | ||||
} | |||||
_serverPermissions = new ServerPermissions(); | |||||
} | |||||
internal override void OnCached() | internal override void OnCached() | ||||
{ | { | ||||
var server = Server; | var server = Server; | ||||
@@ -133,7 +135,7 @@ namespace Discord | |||||
if (model.Roles != null) | if (model.Roles != null) | ||||
UpdateRoles(model.Roles); | UpdateRoles(model.Roles); | ||||
UpdatePermissions(); | |||||
UpdateServerPermissions(); | |||||
} | } | ||||
internal void Update(ExtendedMemberInfo model) | internal void Update(ExtendedMemberInfo model) | ||||
{ | { | ||||
@@ -195,35 +197,27 @@ namespace Discord | |||||
if (LastActivityAt == null || activity > LastActivityAt.Value) | if (LastActivityAt == null || activity > LastActivityAt.Value) | ||||
LastActivityAt = activity ?? DateTime.UtcNow; | LastActivityAt = activity ?? DateTime.UtcNow; | ||||
} | } | ||||
internal void UpdatePermissions() | |||||
{ | |||||
foreach (var channel in _channels) | |||||
UpdatePermissions(channel.Value); | |||||
} | |||||
internal void UpdatePermissions(Channel channel) | |||||
internal void UpdateChannelPermissions(Channel channel) | |||||
{ | { | ||||
if (_roleIds == null) return; // We don't have all our data processed yet, this will be called again soon | if (_roleIds == null) return; // We don't have all our data processed yet, this will be called again soon | ||||
var server = Server; | var server = Server; | ||||
if (server == null || channel.Server != server) return; | if (server == null || channel.Server != server) return; | ||||
ChannelPermissions permissions; | ChannelPermissions permissions; | ||||
if (!_permissions.TryGetValue(channel.Id, out permissions)) return; | if (!_permissions.TryGetValue(channel.Id, out permissions)) return; | ||||
uint newPermissions = 0x0; | |||||
uint newPermissions = _serverPermissions.RawValue; | |||||
uint oldPermissions = permissions.RawValue; | uint oldPermissions = permissions.RawValue; | ||||
if (server.Owner == this) | if (server.Owner == this) | ||||
newPermissions = ChannelPermissions.All(channel).RawValue; | newPermissions = ChannelPermissions.All(channel).RawValue; | ||||
else | else | ||||
{ | { | ||||
if (channel == null) return; | |||||
var channelOverwrites = channel.PermissionOverwrites; | var channelOverwrites = channel.PermissionOverwrites; | ||||
//var roles = Roles.OrderBy(x => x.Id); | //var roles = Roles.OrderBy(x => x.Id); | ||||
var roles = Roles; | var roles = Roles; | ||||
foreach (var serverRole in roles) | |||||
newPermissions |= serverRole.Permissions.RawValue; | |||||
foreach (var denyRole in channelOverwrites.Where(x => x.TargetType == PermissionTarget.Role && x.Deny.RawValue != 0 && roles.Any(y => y.Id == x.TargetId))) | foreach (var denyRole in channelOverwrites.Where(x => x.TargetType == PermissionTarget.Role && x.Deny.RawValue != 0 && roles.Any(y => y.Id == x.TargetId))) | ||||
newPermissions &= ~denyRole.Deny.RawValue; | newPermissions &= ~denyRole.Deny.RawValue; | ||||
foreach (var allowRole in channelOverwrites.Where(x => x.TargetType == PermissionTarget.Role && x.Allow.RawValue != 0 && roles.Any(y => y.Id == x.TargetId))) | foreach (var allowRole in channelOverwrites.Where(x => x.TargetType == PermissionTarget.Role && x.Allow.RawValue != 0 && roles.Any(y => y.Id == x.TargetId))) | ||||
@@ -234,18 +228,49 @@ namespace Discord | |||||
newPermissions |= allowMembers.Allow.RawValue; | newPermissions |= allowMembers.Allow.RawValue; | ||||
} | } | ||||
if (BitHelper.GetBit(newPermissions, (int)PermissionsBits.ManageRolesOrPermissions)) | |||||
newPermissions = ChannelPermissions.All(channel).RawValue; | |||||
if (newPermissions != oldPermissions) | |||||
{ | |||||
permissions.SetRawValueInternal(newPermissions); | |||||
channel.InvalidMembersCache(); | |||||
} | |||||
permissions.SetRawValueInternal(newPermissions); | permissions.SetRawValueInternal(newPermissions); | ||||
} | |||||
internal void UpdateServerPermissions() | |||||
{ | |||||
if (_roleIds == null) return; // We don't have all our data processed yet, this will be called again soon | |||||
if (permissions.ManagePermissions) | |||||
permissions.SetRawValueInternal(ChannelPermissions.All(channel).RawValue); | |||||
/*else if (server.DefaultChannelId == channelId) | |||||
permissions.SetBitInternal(PackedPermissions.Text_ReadMessagesBit, true);*/ | |||||
var server = Server; | |||||
if (server == null) return; | |||||
uint newPermissions = 0x0; | |||||
uint oldPermissions = _serverPermissions.RawValue; | |||||
if (permissions.RawValue != oldPermissions) | |||||
channel.InvalidMembersCache(); | |||||
if (server.Owner == this) | |||||
newPermissions = ServerPermissions.All.RawValue; | |||||
else | |||||
{ | |||||
//var roles = Roles.OrderBy(x => x.Id); | |||||
var roles = Roles; | |||||
foreach (var serverRole in roles) | |||||
newPermissions |= serverRole.Permissions.RawValue; | |||||
} | |||||
if (BitHelper.GetBit(newPermissions, (int)PermissionsBits.ManageRolesOrPermissions)) | |||||
newPermissions = ServerPermissions.All.RawValue; | |||||
if (newPermissions != oldPermissions) | |||||
{ | |||||
_serverPermissions.SetRawValueInternal(newPermissions); | |||||
foreach (var channel in _channels) | |||||
UpdateChannelPermissions(channel.Value); | |||||
} | |||||
} | } | ||||
//TODO: Add GetServerPermissions | |||||
public ChannelPermissions GetPermissions(Channel channel) | |||||
public ServerPermissions GetPermissions() => _serverPermissions; | |||||
public ChannelPermissions GetPermissions(Channel channel) | |||||
{ | { | ||||
if (channel == null) throw new ArgumentNullException(nameof(channel)); | if (channel == null) throw new ArgumentNullException(nameof(channel)); | ||||
@@ -261,7 +286,7 @@ namespace Discord | |||||
perms.Lock(); | perms.Lock(); | ||||
_channels.TryAdd(channel.Id, channel); | _channels.TryAdd(channel.Id, channel); | ||||
_permissions.TryAdd(channel.Id, perms); | _permissions.TryAdd(channel.Id, perms); | ||||
UpdatePermissions(channel); | |||||
UpdateChannelPermissions(channel); | |||||
} | } | ||||
internal void RemoveChannel(Channel channel) | internal void RemoveChannel(Channel channel) | ||||
{ | { | ||||