| @@ -365,7 +365,7 @@ namespace Discord | |||||
| private PrivateChannel AddPrivateChannel(APIChannel model) | private PrivateChannel AddPrivateChannel(APIChannel model) | ||||
| { | { | ||||
| IChannel channel; | IChannel channel; | ||||
| if (_channels.TryGetOrAdd(model.Id, x => new PrivateChannel(x, new User(this, model.Recipient.Id, null), model), out channel)) | |||||
| if (_channels.TryGetOrAdd(model.Id, x => new PrivateChannel(x, new User(model.Recipient, this, null), model), out channel)) | |||||
| _privateChannels[model.Recipient.Id] = channel as PrivateChannel; | _privateChannels[model.Recipient.Id] = channel as PrivateChannel; | ||||
| return channel as PrivateChannel; | return channel as PrivateChannel; | ||||
| } | } | ||||
| @@ -407,7 +407,7 @@ namespace Discord | |||||
| try | try | ||||
| { | { | ||||
| var response = await ClientAPI.Send(new GetInviteRequest(inviteIdOrXkcd)).ConfigureAwait(false); | var response = await ClientAPI.Send(new GetInviteRequest(inviteIdOrXkcd)).ConfigureAwait(false); | ||||
| var invite = new Invite(this, response.Code, response.XkcdPass); | |||||
| var invite = new Invite(response, this); | |||||
| invite.Update(response); | invite.Update(response); | ||||
| return invite; | return invite; | ||||
| } | } | ||||
| @@ -430,7 +430,7 @@ namespace Discord | |||||
| #endregion | #endregion | ||||
| #region Servers | #region Servers | ||||
| private Server AddServer(ulong id) => _servers.GetOrAdd(id, x => new Server(this, x)); | |||||
| private Server AddServer(ulong id) => _servers.GetOrAdd(id, x => new Server(x, this)); | |||||
| private Server RemoveServer(ulong id) | private Server RemoveServer(ulong id) | ||||
| { | { | ||||
| Server server; | Server server; | ||||
| @@ -494,9 +494,9 @@ namespace Discord | |||||
| List<ulong> largeServers = new List<ulong>(); | List<ulong> largeServers = new List<ulong>(); | ||||
| SessionId = data.SessionId; | SessionId = data.SessionId; | ||||
| PrivateUser = new User(this, data.User.Id, null); | |||||
| PrivateUser = new User(data.User, this, null); | |||||
| PrivateUser.Update(data.User); | PrivateUser.Update(data.User); | ||||
| CurrentUser = new Profile(this, data.User.Id); | |||||
| CurrentUser = new Profile(data.User, this); | |||||
| CurrentUser.Update(data.User); | CurrentUser.Update(data.User); | ||||
| for (int i = 0; i < data.Guilds.Length; i++) | for (int i = 0; i < data.Guilds.Length; i++) | ||||
| @@ -633,7 +633,7 @@ namespace Discord | |||||
| var server = GetServer(data.GuildId.Value); | var server = GetServer(data.GuildId.Value); | ||||
| if (server != null) | if (server != null) | ||||
| { | { | ||||
| var user = server.AddUser(data.User.Id, true, true); | |||||
| var user = server.AddUser(data, true, true); | |||||
| user.Update(data); | user.Update(data); | ||||
| user.UpdateActivity(); | user.UpdateActivity(); | ||||
| Logger.Info($"GUILD_MEMBER_ADD: {user}"); | Logger.Info($"GUILD_MEMBER_ADD: {user}"); | ||||
| @@ -691,7 +691,7 @@ namespace Discord | |||||
| { | { | ||||
| foreach (var memberData in data.Members) | foreach (var memberData in data.Members) | ||||
| { | { | ||||
| var user = server.AddUser(memberData.User.Id, true, false); | |||||
| var user = server.AddUser(memberData, true, false); | |||||
| user.Update(memberData); | user.Update(memberData); | ||||
| } | } | ||||
| Logger.Verbose($"GUILD_MEMBERS_CHUNK: {data.Members.Length} users"); | Logger.Verbose($"GUILD_MEMBERS_CHUNK: {data.Members.Length} users"); | ||||
| @@ -796,7 +796,7 @@ namespace Discord | |||||
| var server = GetServer(data.GuildId.Value); | var server = GetServer(data.GuildId.Value); | ||||
| if (server != null) | if (server != null) | ||||
| { | { | ||||
| var user = new User(this, data.User.Id, server); | |||||
| var user = new User(data.User, this, server); | |||||
| user.Update(data.User); | user.Update(data.User); | ||||
| Logger.Info($"GUILD_BAN_REMOVE: {user}"); | Logger.Info($"GUILD_BAN_REMOVE: {user}"); | ||||
| OnUserUnbanned(user); | OnUserUnbanned(user); | ||||
| @@ -819,9 +819,7 @@ namespace Discord | |||||
| if (user != null) | if (user != null) | ||||
| { | { | ||||
| Message msg = null; | Message msg = null; | ||||
| msg = (channel as Channel).MessageManager.Add(data.Id, user, data.Timestamp.Value); | |||||
| msg.Update(data); | |||||
| msg = (channel as Channel).MessageManager.Add(data, user); | |||||
| user.UpdateActivity(); | user.UpdateActivity(); | ||||
| Logger.Verbose($"MESSAGE_CREATE: {channel} ({user})"); | Logger.Verbose($"MESSAGE_CREATE: {channel} ({user})"); | ||||
| @@ -0,0 +1,7 @@ | |||||
| namespace Discord | |||||
| { | |||||
| public interface IPrivateChannel : IChannel | |||||
| { | |||||
| User Recipient { get; } | |||||
| } | |||||
| } | |||||
| @@ -88,20 +88,24 @@ namespace Discord | |||||
| /// <summary> Returns a URL for this invite using XkcdCode if available or Id if not. </summary> | /// <summary> Returns a URL for this invite using XkcdCode if available or Id if not. </summary> | ||||
| public string Url => $"{DiscordConfig.InviteUrl}/{Code}"; | public string Url => $"{DiscordConfig.InviteUrl}/{Code}"; | ||||
| internal Invite(DiscordClient client, string code, string xkcdPass) | |||||
| internal Invite(APIInvite model, DiscordClient client) | |||||
| : this(model.Code, model.XkcdPass) | |||||
| { | { | ||||
| Client = client; | Client = client; | ||||
| Update(model); | |||||
| } | |||||
| internal Invite(InviteReference model, DiscordClient client) | |||||
| : this(model.Code, model.XkcdPass) | |||||
| { | |||||
| Client = client; | |||||
| Update(model); | |||||
| } | |||||
| private Invite(string code, string xkcdCode) | |||||
| { | |||||
| Code = code; | Code = code; | ||||
| XkcdCode = xkcdPass; | |||||
| } | |||||
| internal void Update(InviteReference model) | |||||
| { | |||||
| if (model.Guild != null) | |||||
| Server = new ServerInfo(model.Guild.Id, model.Guild.Name); | |||||
| if (model.Channel != null) | |||||
| Channel = new ChannelInfo(model.Channel.Id, model.Channel.Name); | |||||
| XkcdCode = xkcdCode; | |||||
| } | } | ||||
| internal void Update(APIInvite model) | internal void Update(APIInvite model) | ||||
| { | { | ||||
| Update(model as InviteReference); | Update(model as InviteReference); | ||||
| @@ -118,8 +122,15 @@ namespace Discord | |||||
| Uses = model.Uses.Value; | Uses = model.Uses.Value; | ||||
| if (model.CreatedAt != null) | if (model.CreatedAt != null) | ||||
| CreatedAt = model.CreatedAt.Value; | CreatedAt = model.CreatedAt.Value; | ||||
| } | |||||
| } | |||||
| internal void Update(InviteReference model) | |||||
| { | |||||
| if (model.Guild != null) | |||||
| Server = new ServerInfo(model.Guild.Id, model.Guild.Name); | |||||
| if (model.Channel != null) | |||||
| Channel = new ChannelInfo(model.Channel.Id, model.Channel.Name); | |||||
| } | |||||
| public async Task Delete() | public async Task Delete() | ||||
| { | { | ||||
| try { await Client.ClientAPI.Send(new DeleteInviteRequest(Code)).ConfigureAwait(false); } | try { await Client.ClientAPI.Send(new DeleteInviteRequest(Code)).ConfigureAwait(false); } | ||||
| @@ -130,11 +141,10 @@ namespace Discord | |||||
| internal Invite Clone() | internal Invite Clone() | ||||
| { | { | ||||
| var result = new Invite(); | |||||
| var result = new Invite(Code, XkcdCode); | |||||
| _cloner(this, result); | _cloner(this, result); | ||||
| return result; | return result; | ||||
| } | } | ||||
| private Invite() { } //Used for cloning | |||||
| public override string ToString() => $"{Server}/{XkcdCode ?? Code}"; | public override string ToString() => $"{Server}/{XkcdCode ?? Code}"; | ||||
| } | } | ||||
| @@ -1,4 +1,5 @@ | |||||
| using Discord.API.Client.Rest; | |||||
| using APIMessage = Discord.API.Client.Message; | |||||
| using Discord.API.Client.Rest; | |||||
| using Discord.Net; | using Discord.Net; | ||||
| using System; | using System; | ||||
| using System.Collections; | using System.Collections; | ||||
| @@ -29,15 +30,16 @@ namespace Discord | |||||
| } | } | ||||
| } | } | ||||
| internal Message Add(ulong id, User user, DateTime timestamp) | |||||
| internal Message Add(APIMessage model, User user) => Add(new Message(model, _channel, user)); | |||||
| internal Message Add(ulong id, User user) => Add(new Message(id, _channel, user)); | |||||
| private Message Add(Message message) | |||||
| { | { | ||||
| Message message = new Message(id, _channel, user); | |||||
| message.State = MessageState.Normal; | message.State = MessageState.Normal; | ||||
| if (_size > 0) | if (_size > 0) | ||||
| { | { | ||||
| if (_messages.TryAdd(id, message)) | |||||
| if (_messages.TryAdd(message.Id, message)) | |||||
| { | { | ||||
| _orderedMessages.Enqueue(id); | |||||
| _orderedMessages.Enqueue(message.Id); | |||||
| ulong msgId; | ulong msgId; | ||||
| while (_orderedMessages.Count > _size && _orderedMessages.TryDequeue(out msgId)) | while (_orderedMessages.Count > _size && _orderedMessages.TryDequeue(out msgId)) | ||||
| @@ -93,15 +95,7 @@ namespace Discord | |||||
| Message msg = null; | Message msg = null; | ||||
| ulong id = x.Author.Id; | ulong id = x.Author.Id; | ||||
| var user = server?.GetUser(id) ?? (_channel as Channel).GetUser(id); | var user = server?.GetUser(id) ?? (_channel as Channel).GetUser(id); | ||||
| /*if (useCache) | |||||
| { | |||||
| msg = Add(x.Id, user, x.Timestamp.Value); | |||||
| if (user != null) | |||||
| user.UpdateActivity(msg.EditedTimestamp ?? msg.Timestamp); | |||||
| } | |||||
| else*/ | |||||
| msg = new Message(x.Id, _channel, user); | |||||
| msg.Update(x); | |||||
| msg = new Message(x, _channel, user); | |||||
| return msg; | return msg; | ||||
| }).ToArray(); | }).ToArray(); | ||||
| } | } | ||||
| @@ -130,11 +124,9 @@ namespace Discord | |||||
| Filename = filename, | Filename = filename, | ||||
| Stream = stream | Stream = stream | ||||
| }; | }; | ||||
| var model = await _channel.Client.ClientAPI.Send(request).ConfigureAwait(false); | |||||
| var response = await _channel.Client.ClientAPI.Send(request).ConfigureAwait(false); | |||||
| var msg = Add(model.Id, (_channel as Channel).CurrentUser, model.Timestamp.Value); | |||||
| msg.Update(model); | |||||
| return msg; | |||||
| return Add(response, (_channel as Channel).CurrentUser); | |||||
| } | } | ||||
| public IEnumerator<Message> GetEnumerator() | public IEnumerator<Message> GetEnumerator() | ||||
| @@ -7,22 +7,6 @@ using APIMessage = Discord.API.Client.Message; | |||||
| namespace Discord | namespace Discord | ||||
| { | { | ||||
| public enum MessageState : byte | |||||
| { | |||||
| /// <summary> Message did not originate from this session, or was successfully sent. </summary> | |||||
| Normal = 0, | |||||
| /// <summary> Message is current queued. </summary> | |||||
| Queued, | |||||
| /// <summary> Message was deleted. </summary> | |||||
| Deleted, | |||||
| /// <summary> Message was deleted before it was sent. </summary> | |||||
| Aborted, | |||||
| /// <summary> Message failed to be sent. </summary> | |||||
| Failed, | |||||
| /// <summary> Message has been removed from cache and will no longer receive updates. </summary> | |||||
| Detached | |||||
| } | |||||
| public class Message | public class Message | ||||
| { | { | ||||
| private readonly static Action<Message, Message> _cloner = DynamicIL.CreateCopyMethod<Message>(); | private readonly static Action<Message, Message> _cloner = DynamicIL.CreateCopyMethod<Message>(); | ||||
| @@ -198,15 +182,19 @@ namespace Discord | |||||
| /// <summary> Returns if this message was sent from the logged-in accounts. </summary> | /// <summary> Returns if this message was sent from the logged-in accounts. </summary> | ||||
| public bool IsAuthor => User != null && User.Id == Client.CurrentUser?.Id; | public bool IsAuthor => User != null && User.Id == Client.CurrentUser?.Id; | ||||
| internal Message(ulong id, ITextChannel channel, User user) | |||||
| internal Message(APIMessage model, ITextChannel channel, User user) | |||||
| : this(model.Id, channel, user) | |||||
| { | { | ||||
| Update(model); | |||||
| } | |||||
| internal Message(ulong id, ITextChannel channel, User user) | |||||
| { | |||||
| Id = id; | Id = id; | ||||
| Channel = channel; | Channel = channel; | ||||
| User = user; | User = user; | ||||
| Attachments = _initialAttachments; | |||||
| Embeds = _initialEmbeds; | |||||
| } | |||||
| Attachments = _initialAttachments; | |||||
| Embeds = _initialEmbeds; | |||||
| } | |||||
| internal void Update(APIMessage model) | internal void Update(APIMessage model) | ||||
| { | { | ||||
| @@ -329,11 +317,10 @@ namespace Discord | |||||
| internal Message Clone() | internal Message Clone() | ||||
| { | { | ||||
| var result = new Message(); | |||||
| var result = new Message(Id, Channel, User); | |||||
| _cloner(this, result); | _cloner(this, result); | ||||
| return result; | return result; | ||||
| } | } | ||||
| private Message() { } //Used for cloning | |||||
| public override string ToString() => $"{User}: {RawText}"; | public override string ToString() => $"{User}: {RawText}"; | ||||
| } | } | ||||
| @@ -1,4 +1,5 @@ | |||||
| using Discord.API.Client.Rest; | |||||
| using Discord.API.Client; | |||||
| using Discord.API.Client.Rest; | |||||
| using System; | using System; | ||||
| using System.IO; | using System.IO; | ||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
| @@ -34,10 +35,14 @@ namespace Discord | |||||
| /// <summary> Gets if the email for this user has been verified. </summary> | /// <summary> Gets if the email for this user has been verified. </summary> | ||||
| public bool? IsVerified { get; private set; } | public bool? IsVerified { get; private set; } | ||||
| internal Profile(DiscordClient client, ulong id) | |||||
| internal Profile(UserReference model, DiscordClient client) | |||||
| : this(model.Id, client) | |||||
| { | |||||
| } | |||||
| private Profile(ulong id, DiscordClient client) | |||||
| { | { | ||||
| Client = client; | |||||
| Id = id; | Id = id; | ||||
| Client = client; | |||||
| } | } | ||||
| internal void Update(APIUser model) | internal void Update(APIUser model) | ||||
| @@ -77,11 +82,10 @@ namespace Discord | |||||
| internal Profile Clone() | internal Profile Clone() | ||||
| { | { | ||||
| var result = new Profile(); | |||||
| var result = new Profile(Id, Client); | |||||
| _cloner(this, result); | _cloner(this, result); | ||||
| return result; | return result; | ||||
| } | } | ||||
| private Profile() { } //Used for cloning | |||||
| public override string ToString() => Name; | public override string ToString() => Name; | ||||
| } | } | ||||
| @@ -97,7 +97,7 @@ namespace Discord | |||||
| }; | }; | ||||
| var response = await Client.ClientAPI.Send(request).ConfigureAwait(false); | var response = await Client.ClientAPI.Send(request).ConfigureAwait(false); | ||||
| var invite = new Invite(Client, response.Code, response.XkcdPass); | |||||
| var invite = new Invite(response, Client); | |||||
| return invite; | return invite; | ||||
| } | } | ||||
| @@ -124,11 +124,10 @@ namespace Discord | |||||
| internal Role Clone() | internal Role Clone() | ||||
| { | { | ||||
| var result = new Role(); | |||||
| var result = new Role(Id, Server); | |||||
| _cloner(this, result); | _cloner(this, result); | ||||
| return result; | return result; | ||||
| } | } | ||||
| private Role() { } //Used for cloning | |||||
| public override string ToString() => $"{Server}/{Name ?? Id.ToString()}"; | public override string ToString() => $"{Server}/{Name ?? Id.ToString()}"; | ||||
| } | } | ||||
| @@ -1,4 +1,5 @@ | |||||
| using APIChannel = Discord.API.Client.Channel; | using APIChannel = Discord.API.Client.Channel; | ||||
| using APIMember = Discord.API.Client.Member; | |||||
| using Discord.API.Client; | using Discord.API.Client; | ||||
| using Discord.API.Client.Rest; | using Discord.API.Client.Rest; | ||||
| using Discord.Net; | using Discord.Net; | ||||
| @@ -112,10 +113,10 @@ namespace Discord | |||||
| /// <summary> Gets the number of roles in this server. </summary> | /// <summary> Gets the number of roles in this server. </summary> | ||||
| public int RoleCount => _roles.Count; | public int RoleCount => _roles.Count; | ||||
| internal Server(DiscordClient client, ulong id) | |||||
| internal Server(ulong id, DiscordClient client) | |||||
| { | { | ||||
| Client = client; | |||||
| Id = id; | Id = id; | ||||
| Client = client; | |||||
| } | } | ||||
| internal void Update(Guild model) | internal void Update(Guild model) | ||||
| @@ -181,7 +182,7 @@ namespace Discord | |||||
| if (model.Members != null) | if (model.Members != null) | ||||
| { | { | ||||
| foreach (var subModel in model.Members) | foreach (var subModel in model.Members) | ||||
| AddUser(subModel.User.Id, true, false).Update(subModel); | |||||
| AddUser(subModel, true, false).Update(subModel); | |||||
| } | } | ||||
| if (model.VoiceStates != null) | if (model.VoiceStates != null) | ||||
| { | { | ||||
| @@ -230,8 +231,7 @@ namespace Discord | |||||
| var response = await Client.ClientAPI.Send(new GetBansRequest(Id)).ConfigureAwait(false); | var response = await Client.ClientAPI.Send(new GetBansRequest(Id)).ConfigureAwait(false); | ||||
| return response.Select(x => | return response.Select(x => | ||||
| { | { | ||||
| var user = new User(Client, x.Id, this); | |||||
| user.Update(x); | |||||
| var user = new User(x, Client, this); | |||||
| return user; | return user; | ||||
| }); | }); | ||||
| } | } | ||||
| @@ -305,12 +305,12 @@ namespace Discord | |||||
| #region Invites | #region Invites | ||||
| /// <summary> Gets all active (non-expired) invites to this server. </summary> | /// <summary> Gets all active (non-expired) invites to this server. </summary> | ||||
| public async Task<IEnumerable<Invite>> GetInvites() | |||||
| public async Task<IEnumerable<Invite>> DownloadInvites() | |||||
| { | { | ||||
| var response = await Client.ClientAPI.Send(new GetInvitesRequest(Id)).ConfigureAwait(false); | var response = await Client.ClientAPI.Send(new GetInvitesRequest(Id)).ConfigureAwait(false); | ||||
| return response.Select(x => | return response.Select(x => | ||||
| { | { | ||||
| var invite = new Invite(Client, x.Code, x.XkcdPass); | |||||
| var invite = new Invite(x, Client); | |||||
| invite.Update(x); | invite.Update(x); | ||||
| return invite; | return invite; | ||||
| }); | }); | ||||
| @@ -429,22 +429,22 @@ namespace Discord | |||||
| #endregion | #endregion | ||||
| #region Users | #region Users | ||||
| internal User AddUser(ulong id, bool cachePerms, bool incrementCount) | |||||
| internal User AddUser(APIMember model, bool cachePerms, bool incrementCount) | |||||
| { | { | ||||
| if (incrementCount) | if (incrementCount) | ||||
| _userCount++; | _userCount++; | ||||
| Member member; | Member member; | ||||
| if (!_users.TryGetValue(id, out member)) //Users can only be added from websocket thread, ignore threadsafety | |||||
| if (!_users.TryGetValue(model.User.Id, out member)) //Users can only be added from websocket thread, ignore threadsafety | |||||
| { | { | ||||
| member = new Member(new User(Client, id, this), ServerPermissions.None); | |||||
| if (id == Client.CurrentUser.Id) | |||||
| member = new Member(new User(model, Client, this), ServerPermissions.None); | |||||
| if (model.User.Id == Client.CurrentUser.Id) | |||||
| { | { | ||||
| member.User.CurrentGame = Client.CurrentGame; | member.User.CurrentGame = Client.CurrentGame; | ||||
| member.User.Status = Client.Status; | member.User.Status = Client.Status; | ||||
| } | } | ||||
| _users[id] = member; | |||||
| _users[model.User.Id] = member; | |||||
| if (cachePerms && Client.Config.UsePermissionsCache) | if (cachePerms && Client.Config.UsePermissionsCache) | ||||
| { | { | ||||
| foreach (var channel in _channels) | foreach (var channel in _channels) | ||||
| @@ -501,11 +501,10 @@ namespace Discord | |||||
| internal Server Clone() | internal Server Clone() | ||||
| { | { | ||||
| var result = new Server(); | |||||
| var result = new Server(Id, Client); | |||||
| _cloner(this, result); | _cloner(this, result); | ||||
| return result; | return result; | ||||
| } | } | ||||
| private Server() { } //Used for cloning | |||||
| public override string ToString() => Name ?? Id.ToIdString(); | public override string ToString() => Name ?? Id.ToIdString(); | ||||
| } | } | ||||
| @@ -19,12 +19,12 @@ namespace Discord | |||||
| [Flags] | [Flags] | ||||
| private enum VoiceState : byte | private enum VoiceState : byte | ||||
| { | { | ||||
| None = 0x0, | |||||
| Normal = 0x0, | |||||
| SelfMuted = 0x01, | SelfMuted = 0x01, | ||||
| SelfDeafened = 0x02, | SelfDeafened = 0x02, | ||||
| ServerMuted = 0x04, | |||||
| ServerDeafened = 0x08, | |||||
| ServerSuppressed = 0x10, | |||||
| ServerMuted = 0x10, | |||||
| ServerDeafened = 0x20, | |||||
| ServerSuppressed = 0x40, | |||||
| } | } | ||||
| internal struct CompositeKey : IEquatable<CompositeKey> | internal struct CompositeKey : IEquatable<CompositeKey> | ||||
| @@ -139,18 +139,42 @@ namespace Discord | |||||
| } | } | ||||
| } | } | ||||
| internal User(DiscordClient client, ulong id, Server server) | |||||
| { | |||||
| internal User(ExtendedMember model, DiscordClient client, Server server) | |||||
| : this(model as APIMember, client, server) | |||||
| { | |||||
| if (model.IsServerMuted == true) | |||||
| _voiceState |= VoiceState.ServerMuted; | |||||
| else if (model.IsServerMuted == false) | |||||
| _voiceState &= ~VoiceState.ServerMuted; | |||||
| if (model.IsServerDeafened == true) | |||||
| _voiceState |= VoiceState.ServerDeafened; | |||||
| else if (model.IsServerDeafened == false) | |||||
| _voiceState &= ~VoiceState.ServerDeafened; | |||||
| } | |||||
| internal User(APIMember model, DiscordClient client, Server server) | |||||
| : this(model.User.Id, client, server) | |||||
| { | |||||
| if (server == null) | |||||
| UpdateRoles(null); | |||||
| Update(model); | |||||
| } | |||||
| internal User(UserReference model, DiscordClient client, Server server) | |||||
| : this(model.Id, client, server) | |||||
| { | |||||
| if (server == null) | |||||
| UpdateRoles(null); | |||||
| Update(model); | |||||
| } | |||||
| private User(ulong id, DiscordClient client, Server server) | |||||
| { | |||||
| Client = client; | Client = client; | ||||
| Id = id; | Id = id; | ||||
| Server = server; | Server = server; | ||||
| _roles = new Dictionary<ulong, Role>(); | |||||
| Status = UserStatus.Offline; | |||||
| if (server == null) | |||||
| UpdateRoles(null); | |||||
| } | |||||
| _roles = new Dictionary<ulong, Role>(); | |||||
| Status = UserStatus.Offline; | |||||
| } | |||||
| internal void Update(UserReference model) | internal void Update(UserReference model) | ||||
| { | { | ||||
| @@ -170,20 +194,6 @@ namespace Discord | |||||
| JoinedAt = model.JoinedAt.Value; | JoinedAt = model.JoinedAt.Value; | ||||
| if (model.Roles != null) | if (model.Roles != null) | ||||
| UpdateRoles(model.Roles.Select(x => Server.GetRole(x))); | UpdateRoles(model.Roles.Select(x => Server.GetRole(x))); | ||||
| } | |||||
| internal void Update(ExtendedMember model) | |||||
| { | |||||
| Update(model as APIMember); | |||||
| if (model.IsServerMuted == true) | |||||
| _voiceState |= VoiceState.ServerMuted; | |||||
| else if (model.IsServerMuted == false) | |||||
| _voiceState &= ~VoiceState.ServerMuted; | |||||
| if (model.IsServerDeafened == true) | |||||
| _voiceState |= VoiceState.ServerDeafened; | |||||
| else if (model.IsServerDeafened == false) | |||||
| _voiceState &= ~VoiceState.ServerDeafened; | |||||
| } | } | ||||
| internal void Update(MemberPresence model) | internal void Update(MemberPresence model) | ||||
| { | { | ||||
| @@ -323,11 +333,10 @@ namespace Discord | |||||
| internal User Clone() | internal User Clone() | ||||
| { | { | ||||
| var result = new User(); | |||||
| var result = new User(Id, Client, Server); | |||||
| _cloner(this, result); | _cloner(this, result); | ||||
| return result; | return result; | ||||
| } | } | ||||
| private User() { } //Used for cloning | |||||
| public override string ToString() | public override string ToString() | ||||
| { | { | ||||
| @@ -0,0 +1,18 @@ | |||||
| namespace Discord | |||||
| { | |||||
| public enum MessageState : byte | |||||
| { | |||||
| /// <summary> Message did not originate from this session, or was successfully sent. </summary> | |||||
| Normal = 0, | |||||
| /// <summary> Message is current queued. </summary> | |||||
| Queued, | |||||
| /// <summary> Message was deleted. </summary> | |||||
| Deleted, | |||||
| /// <summary> Message was deleted before it was sent. </summary> | |||||
| Aborted, | |||||
| /// <summary> Message failed to be sent. </summary> | |||||
| Failed, | |||||
| /// <summary> Message has been removed from cache and will no longer receive updates. </summary> | |||||
| Detached | |||||
| } | |||||
| } | |||||
| @@ -1,377 +0,0 @@ | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.IO; | |||||
| using System.Threading.Tasks; | |||||
| namespace Discord.Legacy | |||||
| { | |||||
| public static class Mention | |||||
| { | |||||
| /// <summary> Returns the string used to create a user mention. </summary> | |||||
| [Obsolete("Use User.Mention instead")] | |||||
| public static string User(User user) | |||||
| => user.Mention; | |||||
| /// <summary> Returns the string used to create a channel mention. </summary> | |||||
| [Obsolete("Use Channel.Mention instead")] | |||||
| public static string Channel(Channel channel) | |||||
| => channel.Mention; | |||||
| /// <summary> Returns the string used to create a mention to everyone in a channel. </summary> | |||||
| [Obsolete("Use Server.EveryoneRole.Mention instead")] | |||||
| public static string Everyone() | |||||
| => $"@everyone"; | |||||
| } | |||||
| public static class LegacyExtensions | |||||
| { | |||||
| [Obsolete("Use DiscordClient.ExecuteAndWait")] | |||||
| public static void Run(this DiscordClient client, Func<Task> asyncAction) | |||||
| { | |||||
| client.ExecuteAndWait(asyncAction); | |||||
| } | |||||
| [Obsolete("Use DiscordClient.Wait")] | |||||
| public static void Run(this DiscordClient client) | |||||
| { | |||||
| client.Wait(); | |||||
| } | |||||
| [Obsolete("Use Server.FindChannels")] | |||||
| public static IEnumerable<Channel> FindChannels(this DiscordClient client, Server server, string name, ChannelType type = null, bool exactMatch = false) | |||||
| { | |||||
| if (server == null) throw new ArgumentNullException(nameof(server)); | |||||
| return server.FindChannels(name, type, exactMatch); | |||||
| } | |||||
| [Obsolete("Use Server.CreateChannel")] | |||||
| public static Task<Channel> CreateChannel(this DiscordClient client, Server server, string name, ChannelType type) | |||||
| { | |||||
| if (server == null) throw new ArgumentNullException(nameof(server)); | |||||
| return server.CreateChannel(name, type); | |||||
| } | |||||
| [Obsolete("Use User.CreateChannel")] | |||||
| public static Task<Channel> CreatePMChannel(this DiscordClient client, User user) | |||||
| { | |||||
| if (user == null) throw new ArgumentNullException(nameof(user)); | |||||
| return user.CreatePMChannel(); | |||||
| } | |||||
| [Obsolete("Use Channel.Edit")] | |||||
| public static Task EditChannel(this DiscordClient client, Channel channel, string name = null, string topic = null, int? position = null) | |||||
| { | |||||
| if (channel == null) throw new ArgumentNullException(nameof(channel)); | |||||
| return channel.Edit(name, topic, position); | |||||
| } | |||||
| [Obsolete("Use Channel.Delete")] | |||||
| public static Task DeleteChannel(this DiscordClient client, Channel channel) | |||||
| { | |||||
| if (channel == null) throw new ArgumentNullException(nameof(channel)); | |||||
| return channel.Delete(); | |||||
| } | |||||
| [Obsolete("Use Server.ReorderChannels")] | |||||
| public static Task ReorderChannels(this DiscordClient client, Server server, IEnumerable<Channel> channels, Channel after = null) | |||||
| { | |||||
| if (server == null) throw new ArgumentNullException(nameof(server)); | |||||
| return server.ReorderChannels(channels, after); | |||||
| } | |||||
| [Obsolete("Use Server.GetInvites")] | |||||
| public static Task<IEnumerable<Invite>> GetInvites(this DiscordClient client, Server server) | |||||
| { | |||||
| if (server == null) throw new ArgumentNullException(nameof(server)); | |||||
| return server.GetInvites(); | |||||
| } | |||||
| [Obsolete("Use Server.CreateInvite")] | |||||
| public static Task<Invite> CreateInvite(this DiscordClient client, Server server, int? maxAge = 1800, int? maxUses = null, bool tempMembership = false, bool withXkcd = false) | |||||
| { | |||||
| if (server == null) throw new ArgumentNullException(nameof(server)); | |||||
| return server.CreateInvite(maxAge, maxUses, tempMembership, withXkcd); | |||||
| } | |||||
| [Obsolete("Use Channel.CreateInvite")] | |||||
| public static Task<Invite> CreateInvite(this DiscordClient client, Channel channel, int? maxAge = 1800, int? maxUses = null, bool tempMembership = false, bool withXkcd = false) | |||||
| { | |||||
| if (channel == null) throw new ArgumentNullException(nameof(channel)); | |||||
| return channel.CreateInvite(maxAge, maxUses, tempMembership, withXkcd); | |||||
| } | |||||
| [Obsolete("Use Invite.Delete")] | |||||
| public static Task DeleteInvite(this DiscordClient client, Invite invite) | |||||
| { | |||||
| if (invite == null) throw new ArgumentNullException(nameof(invite)); | |||||
| return invite.Delete(); | |||||
| } | |||||
| [Obsolete("Use Invite.Accept")] | |||||
| public static Task AcceptInvite(this DiscordClient client, Invite invite) | |||||
| { | |||||
| if (invite == null) throw new ArgumentNullException(nameof(invite)); | |||||
| return invite.Accept(); | |||||
| } | |||||
| [Obsolete("Use Channel.SendMessage")] | |||||
| public static Task<Message> SendMessage(this DiscordClient client, Channel channel, string text) | |||||
| { | |||||
| if (channel == null) throw new ArgumentNullException(nameof(channel)); | |||||
| return channel.SendMessage(text); | |||||
| } | |||||
| [Obsolete("Use Channel.SendTTSMessage")] | |||||
| public static Task<Message> SendTTSMessage(this DiscordClient client, Channel channel, string text) | |||||
| { | |||||
| if (channel == null) throw new ArgumentNullException(nameof(channel)); | |||||
| return channel.SendTTSMessage(text); | |||||
| } | |||||
| [Obsolete("Use Channel.SendFile")] | |||||
| public static Task<Message> SendFile(this DiscordClient client, Channel channel, string filePath) | |||||
| { | |||||
| if (channel == null) throw new ArgumentNullException(nameof(channel)); | |||||
| return channel.SendFile(filePath); | |||||
| } | |||||
| [Obsolete("Use Channel.SendFile")] | |||||
| public static Task<Message> SendFile(this DiscordClient client, Channel channel, string filename, Stream stream) | |||||
| { | |||||
| if (channel == null) throw new ArgumentNullException(nameof(channel)); | |||||
| return channel.SendFile(filename, stream); | |||||
| } | |||||
| [Obsolete("Use User.SendMessage")] | |||||
| public static Task<Message> SendMessage(this DiscordClient client, User user, string text) | |||||
| { | |||||
| if (user == null) throw new ArgumentNullException(nameof(user)); | |||||
| return user.SendMessage(text); | |||||
| } | |||||
| [Obsolete("Use User.SendFile")] | |||||
| public static Task<Message> SendFile(this DiscordClient client, User user, string filePath) | |||||
| { | |||||
| if (user == null) throw new ArgumentNullException(nameof(user)); | |||||
| return user.SendFile(filePath); | |||||
| } | |||||
| [Obsolete("Use User.SendFile")] | |||||
| public static Task<Message> SendFile(this DiscordClient client, User user, string filename, Stream stream) | |||||
| { | |||||
| if (user == null) throw new ArgumentNullException(nameof(user)); | |||||
| return user.SendFile(filename, stream); | |||||
| } | |||||
| [Obsolete("Use Message.Edit")] | |||||
| public static Task EditMessage(this DiscordClient client, Message message, string text) | |||||
| { | |||||
| if (message == null) throw new ArgumentNullException(nameof(message)); | |||||
| return message.Edit(text); | |||||
| } | |||||
| [Obsolete("Use Message.Delete")] | |||||
| public static Task DeleteMessage(this DiscordClient client, Message message) | |||||
| { | |||||
| if (message == null) throw new ArgumentNullException(nameof(message)); | |||||
| return message.Delete(); | |||||
| } | |||||
| [Obsolete("Use Message.Delete")] | |||||
| public static async Task DeleteMessages(this DiscordClient client, IEnumerable<Message> messages) | |||||
| { | |||||
| if (messages == null) throw new ArgumentNullException(nameof(messages)); | |||||
| foreach (var message in messages) | |||||
| await message.Delete().ConfigureAwait(false); | |||||
| } | |||||
| [Obsolete("Use Channel.DownloadMessages")] | |||||
| public static Task<Message[]> DownloadMessages(this DiscordClient client, Channel channel, int limit = 100, ulong? relativeMessageId = null, Relative relativeDir = Relative.Before, bool useCache = true) | |||||
| { | |||||
| if (channel == null) throw new ArgumentNullException(nameof(channel)); | |||||
| return channel.DownloadMessages(limit, relativeMessageId, relativeDir, useCache); | |||||
| } | |||||
| [Obsolete("Use Server.GetUser")] | |||||
| public static User GetUser(this DiscordClient client, Server server, ulong userId) | |||||
| { | |||||
| if (server == null) throw new ArgumentNullException(nameof(server)); | |||||
| return server.GetUser(userId); | |||||
| } | |||||
| [Obsolete("Use Server.GetUser")] | |||||
| public static User GetUser(this DiscordClient client, Server server, string username, ushort discriminator) | |||||
| { | |||||
| if (server == null) throw new ArgumentNullException(nameof(server)); | |||||
| return server.GetUser(username, discriminator); | |||||
| } | |||||
| [Obsolete("Use Server.FindUsers")] | |||||
| public static IEnumerable<User> FindUsers(this DiscordClient client, Server server, string name, bool exactMatch = false) | |||||
| { | |||||
| if (server == null) throw new ArgumentNullException(nameof(server)); | |||||
| return server.FindUsers(name, exactMatch); | |||||
| } | |||||
| [Obsolete("Use Channel.FindUsers")] | |||||
| public static IEnumerable<User> FindUsers(this DiscordClient client, Channel channel, string name, bool exactMatch = false) | |||||
| { | |||||
| if (channel == null) throw new ArgumentNullException(nameof(channel)); | |||||
| return channel.FindUsers(name, exactMatch); | |||||
| } | |||||
| [Obsolete("Use User.Edit")] | |||||
| public static Task EditUser(this DiscordClient client, User user, bool? isMuted = null, bool? isDeafened = null, Channel voiceChannel = null, IEnumerable<Role> roles = null) | |||||
| { | |||||
| if (user == null) throw new ArgumentNullException(nameof(user)); | |||||
| return user.Edit(isMuted, isDeafened, voiceChannel, roles); | |||||
| } | |||||
| [Obsolete("Use User.Kick")] | |||||
| public static Task KickUser(this DiscordClient client, User user) | |||||
| { | |||||
| if (user == null) throw new ArgumentNullException(nameof(user)); | |||||
| return user.Kick(); | |||||
| } | |||||
| [Obsolete("Use Server.Ban")] | |||||
| public static Task BanUser(this DiscordClient client, User user, int pruneDays = 0) | |||||
| { | |||||
| if (user == null) throw new ArgumentNullException(nameof(user)); | |||||
| var server = user.Server; | |||||
| if (server == null) throw new ArgumentNullException(nameof(server)); | |||||
| return server.Ban(user, pruneDays); | |||||
| } | |||||
| [Obsolete("Use Server.Unban")] | |||||
| public static Task UnbanUser(this DiscordClient client, User user) | |||||
| { | |||||
| if (user == null) throw new ArgumentNullException(nameof(user)); | |||||
| var server = user.Server; | |||||
| if (server == null) throw new ArgumentNullException(nameof(server)); | |||||
| return server.Unban(user); | |||||
| } | |||||
| [Obsolete("Use Server.Unban")] | |||||
| public static Task UnbanUser(this DiscordClient client, Server server, ulong userId) | |||||
| { | |||||
| if (server == null) throw new ArgumentNullException(nameof(server)); | |||||
| return server.Unban(userId); | |||||
| } | |||||
| [Obsolete("Use Server.PruneUsers")] | |||||
| public static Task<int> PruneUsers(this DiscordClient client, Server server, int days = 30, bool simulate = false) | |||||
| { | |||||
| if (server == null) throw new ArgumentNullException(nameof(server)); | |||||
| return server.PruneUsers(days, simulate); | |||||
| } | |||||
| [Obsolete("Use DiscordClient.CurrentUser.Edit")] | |||||
| public static Task EditProfile(this DiscordClient client, string currentPassword = "", | |||||
| string username = null, string email = null, string password = null, | |||||
| Stream avatar = null, ImageType avatarType = ImageType.Png) | |||||
| => client.CurrentUser.Edit(currentPassword, username, email, password, avatar, avatarType); | |||||
| [Obsolete("Use Server.GetRole")] | |||||
| public static Role GetRole(this DiscordClient client, Server server, ulong id) | |||||
| { | |||||
| if (server == null) throw new ArgumentNullException(nameof(server)); | |||||
| return server.GetRole(id); | |||||
| } | |||||
| [Obsolete("Use Server.FindRoles")] | |||||
| public static IEnumerable<Role> FindRoles(this DiscordClient client, Server server, string name) | |||||
| { | |||||
| if (server == null) throw new ArgumentNullException(nameof(server)); | |||||
| return server.FindRoles(name); | |||||
| } | |||||
| [Obsolete("Use Server.CreateRole")] | |||||
| public static Task<Role> CreateRole(this DiscordClient client, Server server, string name, ServerPermissions? permissions = null, Color color = null, bool isHoisted = false) | |||||
| { | |||||
| if (server == null) throw new ArgumentNullException(nameof(server)); | |||||
| return server.CreateRole(name, permissions, color); | |||||
| } | |||||
| [Obsolete("Use Role.Edit")] | |||||
| public static Task EditRole(this DiscordClient client, Role role, string name = null, ServerPermissions? permissions = null, Color color = null, bool? isHoisted = null, int? position = null) | |||||
| { | |||||
| if (role == null) throw new ArgumentNullException(nameof(role)); | |||||
| return role.Edit(name, permissions, color, isHoisted, position); | |||||
| } | |||||
| [Obsolete("Use Role.Delete")] | |||||
| public static Task DeleteRole(this DiscordClient client, Role role) | |||||
| { | |||||
| if (role == null) throw new ArgumentNullException(nameof(role)); | |||||
| return role.Delete(); | |||||
| } | |||||
| [Obsolete("Use Server.ReorderRoles")] | |||||
| public static Task ReorderRoles(this DiscordClient client, Server server, IEnumerable<Role> roles, Role after = null) | |||||
| { | |||||
| if (server == null) throw new ArgumentNullException(nameof(server)); | |||||
| return server.ReorderRoles(roles, after); | |||||
| } | |||||
| [Obsolete("Use Server.Edit")] | |||||
| public static Task EditServer(this DiscordClient client, Server server, string name = null, string region = null, Stream icon = null, ImageType iconType = ImageType.Png) | |||||
| { | |||||
| if (server == null) throw new ArgumentNullException(nameof(server)); | |||||
| return server.Edit(name, region, icon, iconType); | |||||
| } | |||||
| [Obsolete("Use Server.Leave")] | |||||
| public static Task LeaveServer(this DiscordClient client, Server server) | |||||
| { | |||||
| if (server == null) throw new ArgumentNullException(nameof(server)); | |||||
| return server.Leave(); | |||||
| } | |||||
| [Obsolete("Use DiscordClient.Regions")] | |||||
| public static IEnumerable<Region> GetVoiceRegions(this DiscordClient client) | |||||
| => client.Regions; | |||||
| [Obsolete("Use Channel.GetPermissionRule")] | |||||
| public static ChannelPermissionOverrides GetChannelPermissions(this DiscordClient client, Channel channel, User user) | |||||
| { | |||||
| if (channel == null) throw new ArgumentNullException(nameof(channel)); | |||||
| return channel.GetPermissionsRule(user); | |||||
| } | |||||
| [Obsolete("Use Channel.GetPermissionRule")] | |||||
| public static ChannelPermissionOverrides GetChannelPermissions(this DiscordClient client, Channel channel, Role role) | |||||
| { | |||||
| if (channel == null) throw new ArgumentNullException(nameof(channel)); | |||||
| return channel.GetPermissionsRule(role); | |||||
| } | |||||
| [Obsolete("Use Channel.AddPermissionRule(DualChannelPermissions)", true)] | |||||
| public static Task SetChannelPermissions(this DiscordClient client, Channel channel, User user, ChannelPermissions allow, ChannelPermissions deny) | |||||
| { | |||||
| throw new InvalidOperationException(); | |||||
| } | |||||
| [Obsolete("Use Channel.AddPermissionRule")] | |||||
| public static Task SetChannelPermissions(this DiscordClient client, Channel channel, User user, ChannelPermissionOverrides permissions) | |||||
| { | |||||
| if (channel == null) throw new ArgumentNullException(nameof(channel)); | |||||
| return channel.AddPermissionsRule(user, permissions); | |||||
| } | |||||
| [Obsolete("Use Channel.AddPermissionRule(DualChannelPermissions)")] | |||||
| public static Task SetChannelPermissions(this DiscordClient client, Channel channel, Role role, ChannelPermissions allow, ChannelPermissions deny) | |||||
| { | |||||
| throw new InvalidOperationException(); | |||||
| } | |||||
| [Obsolete("Use Channel.AddPermissionRule")] | |||||
| public static Task SetChannelPermissions(this DiscordClient client, Channel channel, Role role, ChannelPermissionOverrides permissions) | |||||
| { | |||||
| if (channel == null) throw new ArgumentNullException(nameof(channel)); | |||||
| return channel.AddPermissionsRule(role, permissions); | |||||
| } | |||||
| [Obsolete("Use Channel.RemovePermissionRule")] | |||||
| public static Task RemoveChannelPermissions(this DiscordClient client, Channel channel, User user) | |||||
| { | |||||
| if (channel == null) throw new ArgumentNullException(nameof(channel)); | |||||
| return channel.RemovePermissionsRule(user); | |||||
| } | |||||
| [Obsolete("Use Channel.RemovePermissionRule")] | |||||
| public static Task RemoveChannelPermissions(this DiscordClient client, Channel channel, Role role) | |||||
| { | |||||
| if (channel == null) throw new ArgumentNullException(nameof(channel)); | |||||
| return channel.RemovePermissionsRule(role); | |||||
| } | |||||
| [Obsolete("Removed", true)] | |||||
| public static Task AckMessage(this DiscordClient client, Message message) | |||||
| { | |||||
| throw new InvalidOperationException(); | |||||
| } | |||||
| [Obsolete("Use Channel.ImportMessages", true)] | |||||
| public static IEnumerable<Message> ImportMessages(Channel channel, string json) | |||||
| { | |||||
| throw new InvalidOperationException(); | |||||
| } | |||||
| [Obsolete("Use Channel.ExportMessages", true)] | |||||
| public static string ExportMessages(Channel channel) | |||||
| { | |||||
| throw new InvalidOperationException(); | |||||
| } | |||||
| } | |||||
| } | |||||