diff --git a/src/Discord.Net.Core/Entities/Roles/IRole.cs b/src/Discord.Net.Core/Entities/Roles/IRole.cs index aa34fb019..2e3d63702 100644 --- a/src/Discord.Net.Core/Entities/Roles/IRole.cs +++ b/src/Discord.Net.Core/Entities/Roles/IRole.cs @@ -4,7 +4,7 @@ using System.Threading.Tasks; namespace Discord { - public interface IRole : ISnowflakeEntity, IDeletable, IMentionable + public interface IRole : ISnowflakeEntity, IDeletable, IMentionable, IComparable { /// Gets the guild owning this role. IGuild Guild { get; } @@ -27,4 +27,4 @@ namespace Discord ///// Modifies this role. Task ModifyAsync(Action func, RequestOptions options = null); } -} \ No newline at end of file +} diff --git a/src/Discord.Net.Core/Extensions/RoleExtensions.cs b/src/Discord.Net.Core/Extensions/RoleExtensions.cs new file mode 100644 index 000000000..bd6856501 --- /dev/null +++ b/src/Discord.Net.Core/Extensions/RoleExtensions.cs @@ -0,0 +1,18 @@ +namespace Discord +{ + internal static class RoleExtensions + { + internal static int Compare(this IRole left, IRole right) + { + if (left == null) + return -1; + if (right == null) + return 1; + var result = left.Position.CompareTo(right.Position); + // As per Discord's documentation, a tie is broken by ID + if (result != 0) + return result; + return left.Id.CompareTo(right.Id); + } + } +} diff --git a/src/Discord.Net.Rest/Entities/Roles/RestRole.cs b/src/Discord.Net.Rest/Entities/Roles/RestRole.cs index cc42fc57d..eee1fdf0a 100644 --- a/src/Discord.Net.Rest/Entities/Roles/RestRole.cs +++ b/src/Discord.Net.Rest/Entities/Roles/RestRole.cs @@ -52,6 +52,8 @@ namespace Discord.Rest public Task DeleteAsync(RequestOptions options = null) => RoleHelper.DeleteAsync(this, Discord, options); + public int CompareTo(IRole role) => this.Compare(role); + public override string ToString() => Name; private string DebuggerDisplay => $"{Name} ({Id})"; diff --git a/src/Discord.Net.WebSocket/Entities/Roles/SocketRole.cs b/src/Discord.Net.WebSocket/Entities/Roles/SocketRole.cs index 515389da1..5fa585138 100644 --- a/src/Discord.Net.WebSocket/Entities/Roles/SocketRole.cs +++ b/src/Discord.Net.WebSocket/Entities/Roles/SocketRole.cs @@ -57,5 +57,6 @@ namespace Discord.WebSocket //IRole IGuild IRole.Guild => Guild; + public int CompareTo(IRole role) => this.CompareTo(role); } } diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs index 5a670c14d..3ef45d230 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs @@ -25,19 +25,39 @@ namespace Discord.WebSocket public override ushort DiscriminatorValue { get { return GlobalUser.DiscriminatorValue; } internal set { GlobalUser.DiscriminatorValue = value; } } public override string AvatarId { get { return GlobalUser.AvatarId; } internal set { GlobalUser.AvatarId = value; } } public GuildPermissions GuildPermissions => new GuildPermissions(Permissions.ResolveGuild(Guild, this)); - public IReadOnlyCollection RoleIds => _roleIds; internal override SocketPresence Presence { get { return GlobalUser.Presence; } set { GlobalUser.Presence = value; } } - public SocketVoiceState? VoiceState => Guild.GetVoiceState(Id); public bool IsSelfDeafened => VoiceState?.IsSelfDeafened ?? false; public bool IsSelfMuted => VoiceState?.IsSelfMuted ?? false; public bool IsSuppressed => VoiceState?.IsSuppressed ?? false; - public SocketVoiceChannel VoiceChannel => VoiceState?.VoiceChannel; public bool IsDeafened => VoiceState?.IsDeafened ?? false; public bool IsMuted => VoiceState?.IsMuted ?? false; + public DateTimeOffset? JoinedAt => DateTimeUtils.FromTicks(_joinedAtTicks); + public IReadOnlyCollection RoleIds => _roleIds; + public SocketVoiceChannel VoiceChannel => VoiceState?.VoiceChannel; public string VoiceSessionId => VoiceState?.VoiceSessionId ?? ""; + public SocketVoiceState? VoiceState => Guild.GetVoiceState(Id); - public DateTimeOffset? JoinedAt => DateTimeUtils.FromTicks(_joinedAtTicks); + /// The position of the user within the role hirearchy. + /// The returned value equal to the position of the highest role the user has, + /// or int.MaxValue if user is the server owner. + public int Hierarchy + { + get + { + if (Guild.OwnerId == Id) + return int.MaxValue; + + int maxPos = 0; + for (int i = 0; i < _roleIds.Length; i++) + { + var role = Guild.GetRole(_roleIds[i]); + if (role != null && role.Position > maxPos) + maxPos = role.Position; + } + return maxPos; + } + } internal SocketGuildUser(SocketGuild guild, SocketGlobalUser globalUser) : base(guild.Discord, globalUser.Id)