diff --git a/src/Discord.Net.Commands/Results/TypeReaderResult.cs b/src/Discord.Net.Commands/Results/TypeReaderResult.cs index 932f1299b..beeabab16 100644 --- a/src/Discord.Net.Commands/Results/TypeReaderResult.cs +++ b/src/Discord.Net.Commands/Results/TypeReaderResult.cs @@ -1,4 +1,5 @@ using System.Diagnostics; +using System.Runtime.InteropServices; namespace Discord.Commands { diff --git a/src/Discord.Net/Entities/Messages/IMessage.cs b/src/Discord.Net/Entities/Messages/IMessage.cs index 3a91336d2..61f1199eb 100644 --- a/src/Discord.Net/Entities/Messages/IMessage.cs +++ b/src/Discord.Net/Entities/Messages/IMessage.cs @@ -30,9 +30,9 @@ namespace Discord IReadOnlyCollection Embeds { get; } /// Returns a collection of channel ids mentioned in this message. IReadOnlyCollection MentionedChannelIds { get; } - /// Returns a collection of role ids mentioned in this message. - IReadOnlyCollection MentionedRoleIds { get; } - /// Returns a collection of user ids mentioned in this message. + /// Returns a collection of roles mentioned in this message. + IReadOnlyCollection MentionedRoles { get; } + /// Returns a collection of users mentioned in this message. IReadOnlyCollection MentionedUsers { get; } /// Modifies this message. diff --git a/src/Discord.Net/Entities/Messages/Message.cs b/src/Discord.Net/Entities/Messages/Message.cs index bd91de78a..e0fba96cb 100644 --- a/src/Discord.Net/Entities/Messages/Message.cs +++ b/src/Discord.Net/Entities/Messages/Message.cs @@ -23,11 +23,11 @@ namespace Discord public IMessageChannel Channel { get; } public IUser Author { get; } - public ImmutableArray Attachments { get; private set; } - public ImmutableArray Embeds { get; private set; } - public ImmutableArray MentionedChannelIds { get; private set; } - public ImmutableArray MentionedRoleIds { get; private set; } - public ImmutableArray MentionedUsers { get; private set; } + public IReadOnlyCollection Attachments { get; private set; } + public IReadOnlyCollection Embeds { get; private set; } + public IReadOnlyCollection MentionedChannelIds { get; private set; } + public IReadOnlyCollection MentionedRoles { get; private set; } + public IReadOnlyCollection MentionedUsers { get; private set; } public override DiscordClient Discord => (Channel as Entity).Discord; public DateTimeOffset? EditedTimestamp => DateTimeUtils.FromTicks(_editedTimestampTicks); @@ -41,9 +41,9 @@ namespace Discord if (channel is IGuildChannel) { - MentionedUsers = ImmutableArray.Create(); + MentionedUsers = ImmutableArray.Create(); MentionedChannelIds = ImmutableArray.Create(); - MentionedRoleIds = ImmutableArray.Create(); + MentionedRoles = ImmutableArray.Create(); } Update(model, UpdateSource.Creation); @@ -106,21 +106,31 @@ namespace Discord MentionedUsers = ImmutableArray.Create(mentions); } else - MentionedUsers = ImmutableArray.Create(); + MentionedUsers = ImmutableArray.Create(); } if (model.Content.IsSpecified) { RawText = model.Content.Value; - - if (Channel is IGuildChannel) + + if (guildChannel != null) { - Text = MentionUtils.CleanUserMentions(RawText, MentionedUsers); - MentionedChannelIds = MentionUtils.GetChannelMentions(RawText); - var mentionedRoleIds = MentionUtils.GetRoleMentions(RawText); - if (_isMentioningEveryone) - mentionedRoleIds = mentionedRoleIds.Add(guildChannel.Guild.EveryoneRole.Id); - MentionedRoleIds = mentionedRoleIds; + var orderedMentionedUsers = ImmutableArray.CreateBuilder(5); + Text = MentionUtils.CleanUserMentions(RawText, Channel.IsAttached ? Channel : null, MentionedUsers, orderedMentionedUsers); + MentionedUsers = orderedMentionedUsers.ToImmutable(); + + var roles = ImmutableArray.CreateBuilder(5); + Text = MentionUtils.CleanRoleMentions(Text, guildChannel.Guild, roles); + MentionedRoles = roles.ToImmutable(); + + if (guildChannel.IsAttached) //It's too expensive to do a channel lookup in REST mode + { + var channelIds = ImmutableArray.CreateBuilder(5); + Text = MentionUtils.CleanChannelMentions(Text, guildChannel.Guild, channelIds); + MentionedChannelIds = channelIds.ToImmutable(); + } + else + MentionedChannelIds = MentionUtils.GetChannelMentions(RawText); } else Text = RawText; @@ -172,12 +182,6 @@ namespace Discord } public override string ToString() => Text; - private string DebuggerDisplay => $"{Author}: {Text}{(Attachments.Length > 0 ? $" [{Attachments.Length} Attachments]" : "")}"; - - IReadOnlyCollection IMessage.Attachments => Attachments; - IReadOnlyCollection IMessage.Embeds => Embeds; - IReadOnlyCollection IMessage.MentionedChannelIds => MentionedChannelIds; - IReadOnlyCollection IMessage.MentionedRoleIds => MentionedRoleIds; - IReadOnlyCollection IMessage.MentionedUsers => MentionedUsers; + private string DebuggerDisplay => $"{Author}: {Text}{(Attachments.Count > 0 ? $" [{Attachments.Count} Attachments]" : "")}"; } } diff --git a/src/Discord.Net/Utilities/MentionUtils.cs b/src/Discord.Net/Utilities/MentionUtils.cs index 1a092fd9c..f348d4962 100644 --- a/src/Discord.Net/Utilities/MentionUtils.cs +++ b/src/Discord.Net/Utilities/MentionUtils.cs @@ -4,6 +4,7 @@ using System.Collections.Immutable; using System.Globalization; using System.Linq; using System.Text.RegularExpressions; +using System.Threading.Tasks; namespace Discord { @@ -107,7 +108,7 @@ namespace Discord return builder; } - internal static string CleanUserMentions(string text, ImmutableArray mentions) + /*internal static string CleanUserMentions(string text, ImmutableArray mentions) { return _userRegex.Replace(text, new MatchEvaluator(e => { @@ -123,58 +124,71 @@ namespace Discord } return e.Value; })); - } - internal static string CleanUserMentions(string text, IReadOnlyDictionary users, ImmutableArray.Builder mentions = null) - where T : IGuildUser + }*/ + internal static string CleanUserMentions(string text, IMessageChannel channel, IReadOnlyCollection fallbackUsers, ImmutableArray.Builder mentions = null) { - return _channelRegex.Replace(text, new MatchEvaluator(e => + return _userRegex.Replace(text, new MatchEvaluator(e => { ulong id; if (ulong.TryParse(e.Groups[1].Value, NumberStyles.None, CultureInfo.InvariantCulture, out id)) { - T user; - if (users.TryGetValue(id, out user)) + IUser user = null; + if (channel != null) + user = channel.GetUserAsync(id).GetAwaiter().GetResult() as IUser; + if (user == null) + { + foreach (var fallbackUser in fallbackUsers) + { + if (fallbackUser.Id == id) + { + user = fallbackUser; + break; + } + } + } + if (user != null) { - if (users != null) - mentions.Add(user); - if (e.Value[2] == '!' && user.Nickname != null) - return '@' + user.Nickname; - else - return '@' + user.Username; + mentions.Add(user); + + if (e.Value[2] == '!') + { + var guildUser = user as IGuildUser; + if (guildUser != null && guildUser.Nickname != null) + return '@' + guildUser.Nickname; + } + return '@' + user.Username; } } return e.Value; })); } - internal static string CleanChannelMentions(string text, IReadOnlyDictionary channels, ImmutableArray.Builder mentions = null) - where T : IGuildChannel + internal static string CleanChannelMentions(string text, IGuild guild, ImmutableArray.Builder mentions = null) { return _channelRegex.Replace(text, new MatchEvaluator(e => { ulong id; if (ulong.TryParse(e.Groups[1].Value, NumberStyles.None, CultureInfo.InvariantCulture, out id)) { - T channel; - if (channels.TryGetValue(id, out channel)) + var channel = guild.GetChannelAsync(id).GetAwaiter().GetResult() as IGuildChannel; + if (channel != null) { - if (channels != null) - mentions.Add(channel); + if (mentions != null) + mentions.Add(channel.Id); return '#' + channel.Name; } } return e.Value; })); } - internal static string CleanRoleMentions(string text, IReadOnlyDictionary roles, ImmutableArray.Builder mentions = null) - where T : IRole + internal static string CleanRoleMentions(string text, IGuild guild, ImmutableArray.Builder mentions = null) { - return _channelRegex.Replace(text, new MatchEvaluator(e => + return _roleRegex.Replace(text, new MatchEvaluator(e => { ulong id; if (ulong.TryParse(e.Groups[1].Value, NumberStyles.None, CultureInfo.InvariantCulture, out id)) { - T role; - if (roles.TryGetValue(id, out role)) + var role = guild.GetRole(id); + if (role != null) { if (mentions != null) mentions.Add(role);