@@ -1,11 +1,14 @@ | |||||
# Discord.Net v1.0.0-dev | # Discord.Net v1.0.0-dev | ||||
[](https://www.nuget.org/packages/Discord.Net) [](https://ci.appveyor.com/project/foxbot/discord-net/) [](https://discord.gg/0SBTUU1wZTYLhAAW) | |||||
[](https://ci.appveyor.com/project/foxbot/discord-net/branch/master) | |||||
Discord.Net is an API wrapper for [Discord](http://discordapp.com) written in C#. | |||||
An unofficial .Net API Wrapper for the Discord client (http://discordapp.com). | |||||
Check out the [documentation](https://discordnet.readthedocs.org/en/latest/) or join the [Discord API Chat](https://discord.gg/0SBTUU1wZTVjAMPx). | |||||
Check out the [documentation](http://rtd.discord.foxbot.me/en/docs-dev/index.html) or join the [Discord API Chat](https://discord.gg/0SBTUU1wZTVjAMPx). | |||||
## Installing | |||||
##### Warning: Some of the documentation is outdated. | |||||
It's current being rewritten. Until that's done, feel free to use my [DiscordBot](https://github.com/RogueException/DiscordBot) repo for reference. | |||||
### Installation | |||||
You can download Discord.Net and its extensions from NuGet: | You can download Discord.Net and its extensions from NuGet: | ||||
- [Discord.Net](https://www.nuget.org/packages/Discord.Net/) | - [Discord.Net](https://www.nuget.org/packages/Discord.Net/) | ||||
- [Discord.Net.Commands](https://www.nuget.org/packages/Discord.Net.Commands/) | - [Discord.Net.Commands](https://www.nuget.org/packages/Discord.Net.Commands/) | ||||
@@ -14,9 +17,8 @@ You can download Discord.Net and its extensions from NuGet: | |||||
### Compiling | ### Compiling | ||||
In order to compile Discord.Net, you require at least the following: | In order to compile Discord.Net, you require at least the following: | ||||
- [Visual Studio 15](https://www.visualstudio.com/downloads/download-visual-studio-vs) | |||||
- [ASP.Net 5 RC1](https://get.asp.net) | |||||
- NuGet 3.3 (available through Visual Studio) | |||||
- [Visual Studio 2015](https://www.visualstudio.com/downloads/download-visual-studio-vs) | |||||
- [Visual Studio 2015 Update 2](https://www.visualstudio.com/en-us/news/vs2015-update2-vs.aspx) | |||||
- [Visual Studio .Net Core Plugin](https://www.microsoft.com/net/core#windows) | |||||
- NuGet 3.3+ (available through Visual Studio) | |||||
### Known Issues | |||||
- .Net Core support is incomplete on non-Windows systems |
@@ -0,0 +1,6 @@ | |||||
{ | |||||
"projects": [ "src", "test" ], | |||||
"sdk": { | |||||
"version": "1.0.0-preview1-002702" | |||||
} | |||||
} |
@@ -10,7 +10,7 @@ namespace Discord.API | |||||
[JsonProperty("is_private")] | [JsonProperty("is_private")] | ||||
public bool IsPrivate { get; set; } | public bool IsPrivate { get; set; } | ||||
[JsonProperty("last_message_id")] | [JsonProperty("last_message_id")] | ||||
public ulong LastMessageId { get; set; } | |||||
public ulong? LastMessageId { get; set; } | |||||
//GuildChannel | //GuildChannel | ||||
[JsonProperty("guild_id")] | [JsonProperty("guild_id")] | ||||
@@ -23,10 +23,16 @@ namespace Discord.API | |||||
public int Position { get; set; } | public int Position { get; set; } | ||||
[JsonProperty("permission_overwrites")] | [JsonProperty("permission_overwrites")] | ||||
public Overwrite[] PermissionOverwrites { get; set; } | public Overwrite[] PermissionOverwrites { get; set; } | ||||
//TextChannel | |||||
[JsonProperty("topic")] | [JsonProperty("topic")] | ||||
public string Topic { get; set; } | public string Topic { get; set; } | ||||
//VoiceChannel | |||||
[JsonProperty("bitrate")] | [JsonProperty("bitrate")] | ||||
public int Bitrate { get; set; } | public int Bitrate { get; set; } | ||||
[JsonProperty("user_limit")] | |||||
public int UserLimit { get; set; } | |||||
//DMChannel | //DMChannel | ||||
[JsonProperty("recipient")] | [JsonProperty("recipient")] | ||||
@@ -0,0 +1,14 @@ | |||||
using Newtonsoft.Json; | |||||
namespace Discord.API | |||||
{ | |||||
public class Game | |||||
{ | |||||
[JsonProperty("name")] | |||||
public string Name { get; set; } | |||||
[JsonProperty("url")] | |||||
public string StreamUrl { get; set; } | |||||
[JsonProperty("type")] | |||||
public StreamType StreamType { get; set; } | |||||
} | |||||
} |
@@ -8,9 +8,9 @@ namespace Discord.API | |||||
public ulong TargetId { get; set; } | public ulong TargetId { get; set; } | ||||
[JsonProperty("type")] | [JsonProperty("type")] | ||||
public PermissionTarget TargetType { get; set; } | public PermissionTarget TargetType { get; set; } | ||||
[JsonProperty("deny")] | |||||
public uint Deny { get; set; } | |||||
[JsonProperty("allow")] | |||||
public uint Allow { get; set; } | |||||
[JsonProperty("deny"), Int53] | |||||
public ulong Deny { get; set; } | |||||
[JsonProperty("allow"), Int53] | |||||
public ulong Allow { get; set; } | |||||
} | } | ||||
} | } |
@@ -9,6 +9,6 @@ namespace Discord.API | |||||
[JsonProperty("mention_count")] | [JsonProperty("mention_count")] | ||||
public int MentionCount { get; set; } | public int MentionCount { get; set; } | ||||
[JsonProperty("last_message_id")] | [JsonProperty("last_message_id")] | ||||
public ulong LastMentionId { get; set; } | |||||
public ulong? LastMessageId { get; set; } | |||||
} | } | ||||
} | } |
@@ -14,8 +14,8 @@ namespace Discord.API | |||||
public bool? Hoist { get; set; } | public bool? Hoist { get; set; } | ||||
[JsonProperty("position")] | [JsonProperty("position")] | ||||
public int? Position { get; set; } | public int? Position { get; set; } | ||||
[JsonProperty("permissions")] | |||||
public uint? Permissions { get; set; } | |||||
[JsonProperty("permissions"), Int53] | |||||
public ulong? Permissions { get; set; } | |||||
[JsonProperty("managed")] | [JsonProperty("managed")] | ||||
public bool? Managed { get; set; } | public bool? Managed { get; set; } | ||||
} | } | ||||
@@ -12,7 +12,7 @@ namespace Discord.API | |||||
public string Icon { get; set; } | public string Icon { get; set; } | ||||
[JsonProperty("owner")] | [JsonProperty("owner")] | ||||
public bool Owner { get; set; } | public bool Owner { get; set; } | ||||
[JsonProperty("permissions")] | |||||
public uint Permissions { get; set; } | |||||
[JsonProperty("permissions"), Int53] | |||||
public ulong Permissions { get; set; } | |||||
} | } | ||||
} | } |
@@ -0,0 +1,24 @@ | |||||
namespace Discord.API.Gateway | |||||
{ | |||||
public enum GatewayOpCodes : byte | |||||
{ | |||||
/// <summary> C←S - Used to send most events. </summary> | |||||
Dispatch = 0, | |||||
/// <summary> C↔S - Used to keep the connection alive and measure latency. </summary> | |||||
Heartbeat = 1, | |||||
/// <summary> C→S - Used to associate a connection with a token and specify configuration. </summary> | |||||
Identify = 2, | |||||
/// <summary> C→S - Used to update client's status and current game id. </summary> | |||||
StatusUpdate = 3, | |||||
/// <summary> C→S - Used to join a particular voice channel. </summary> | |||||
VoiceStateUpdate = 4, | |||||
/// <summary> C→S - Used to ensure the server's voice server is alive. Only send this if voice connection fails or suddenly drops. </summary> | |||||
VoiceServerPing = 5, | |||||
/// <summary> C→S - Used to resume a connection after a redirect occurs. </summary> | |||||
Resume = 6, | |||||
/// <summary> C←S - Used to notify a client that they must reconnect to another gateway. </summary> | |||||
Reconnect = 7, | |||||
/// <summary> C→S - Used to request all members that were withheld by large_threshold </summary> | |||||
RequestGuildMembers = 8 | |||||
} | |||||
} |
@@ -0,0 +1,12 @@ | |||||
using Newtonsoft.Json; | |||||
namespace Discord.API.Gateway | |||||
{ | |||||
public class GuildMembersChunkEvent | |||||
{ | |||||
[JsonProperty("guild_id")] | |||||
public ulong GuildId { get; set; } | |||||
[JsonProperty("members")] | |||||
public GuildMember[] Members { get; set; } | |||||
} | |||||
} |
@@ -0,0 +1,12 @@ | |||||
using Newtonsoft.Json; | |||||
namespace Discord.API.Gateway | |||||
{ | |||||
public class GuildRoleCreateEvent | |||||
{ | |||||
[JsonProperty("guild_id")] | |||||
public ulong GuildId { get; set; } | |||||
[JsonProperty("role")] | |||||
public Role Data { get; set; } | |||||
} | |||||
} |
@@ -0,0 +1,12 @@ | |||||
using Newtonsoft.Json; | |||||
namespace Discord.API.Gateway | |||||
{ | |||||
public class GuildRoleUpdateEvent | |||||
{ | |||||
[JsonProperty("guild_id")] | |||||
public ulong GuildId { get; set; } | |||||
[JsonProperty("role")] | |||||
public Role Data { get; set; } | |||||
} | |||||
} |
@@ -0,0 +1,17 @@ | |||||
using Newtonsoft.Json; | |||||
using System.Collections.Generic; | |||||
namespace Discord.API.Gateway | |||||
{ | |||||
public class IdentifyParams | |||||
{ | |||||
[JsonProperty("token")] | |||||
public string Token { get; set; } | |||||
[JsonProperty("properties")] | |||||
public IDictionary<string, string> Properties { get; set; } | |||||
[JsonProperty("large_threshold")] | |||||
public int LargeThreshold { get; set; } | |||||
[JsonProperty("compress")] | |||||
public bool UseCompression { get; set; } | |||||
} | |||||
} |
@@ -0,0 +1,40 @@ | |||||
using Newtonsoft.Json; | |||||
namespace Discord.API.Gateway | |||||
{ | |||||
public class ReadyEvent | |||||
{ | |||||
public class ReadState | |||||
{ | |||||
[JsonProperty("id")] | |||||
public string ChannelId { get; set; } | |||||
[JsonProperty("mention_count")] | |||||
public int MentionCount { get; set; } | |||||
[JsonProperty("last_message_id")] | |||||
public string LastMessageId { get; set; } | |||||
} | |||||
[JsonProperty("v")] | |||||
public int Version { get; set; } | |||||
[JsonProperty("user")] | |||||
public User User { get; set; } | |||||
[JsonProperty("session_id")] | |||||
public string SessionId { get; set; } | |||||
[JsonProperty("read_state")] | |||||
public ReadState[] ReadStates { get; set; } | |||||
[JsonProperty("guilds")] | |||||
public Guild[] Guilds { get; set; } | |||||
[JsonProperty("private_channels")] | |||||
public Channel[] PrivateChannels { get; set; } | |||||
[JsonProperty("heartbeat_interval")] | |||||
public int HeartbeatInterval { get; set; } | |||||
//Ignored | |||||
[JsonProperty("user_settings")] | |||||
public object UserSettings { get; set; } | |||||
[JsonProperty("user_guild_settings")] | |||||
public object UserGuildSettings { get; set; } | |||||
[JsonProperty("tutorial")] | |||||
public object Tutorial { get; set; } | |||||
} | |||||
} |
@@ -0,0 +1,14 @@ | |||||
using Newtonsoft.Json; | |||||
namespace Discord.API.Gateway | |||||
{ | |||||
public class RequestMembersParams | |||||
{ | |||||
[JsonProperty("guild_id")] | |||||
public ulong[] GuildId { get; set; } | |||||
[JsonProperty("query")] | |||||
public string Query { get; set; } | |||||
[JsonProperty("limit")] | |||||
public int Limit { get; set; } | |||||
} | |||||
} |
@@ -0,0 +1,12 @@ | |||||
using Newtonsoft.Json; | |||||
namespace Discord.API.Gateway | |||||
{ | |||||
public class ResumeParams | |||||
{ | |||||
[JsonProperty("session_id")] | |||||
public string SessionId { get; set; } | |||||
[JsonProperty("seq")] | |||||
public uint Sequence { get; set; } | |||||
} | |||||
} |
@@ -0,0 +1,10 @@ | |||||
using Newtonsoft.Json; | |||||
namespace Discord.API.Gateway | |||||
{ | |||||
public class ResumedEvent | |||||
{ | |||||
[JsonProperty("heartbeat_interval")] | |||||
public int HeartbeatInterval { get; set; } | |||||
} | |||||
} |
@@ -0,0 +1,14 @@ | |||||
using Newtonsoft.Json; | |||||
namespace Discord.API.Gateway | |||||
{ | |||||
public class TypingStartEvent | |||||
{ | |||||
[JsonProperty("user_id")] | |||||
public ulong UserId { get; set; } | |||||
[JsonProperty("channel_id")] | |||||
public ulong ChannelId { get; set; } | |||||
[JsonProperty("timestamp")] | |||||
public int Timestamp { get; set; } | |||||
} | |||||
} |
@@ -0,0 +1,12 @@ | |||||
using Newtonsoft.Json; | |||||
namespace Discord.API.Gateway | |||||
{ | |||||
public class UpdateStatusParams | |||||
{ | |||||
[JsonProperty("idle_since")] | |||||
public long? IdleSince { get; set; } | |||||
[JsonProperty("game")] | |||||
public Game Game { get; set; } | |||||
} | |||||
} |
@@ -0,0 +1,16 @@ | |||||
using Newtonsoft.Json; | |||||
namespace Discord.API.Gateway | |||||
{ | |||||
public class UpdateVoiceParams | |||||
{ | |||||
[JsonProperty("guild_id")] | |||||
public ulong? GuildId { get; set; } | |||||
[JsonProperty("channel_id")] | |||||
public ulong? ChannelId { get; set; } | |||||
[JsonProperty("self_mute")] | |||||
public bool IsSelfMuted { get; set; } | |||||
[JsonProperty("self_deaf")] | |||||
public bool IsSelfDeafened { get; set; } | |||||
} | |||||
} |
@@ -0,0 +1,14 @@ | |||||
using Newtonsoft.Json; | |||||
namespace Discord.API.Gateway | |||||
{ | |||||
public class VoiceServerUpdateEvent | |||||
{ | |||||
[JsonProperty("guild_id")] | |||||
public ulong GuildId { get; set; } | |||||
[JsonProperty("endpoint")] | |||||
public string Endpoint { get; set; } | |||||
[JsonProperty("token")] | |||||
public string Token { get; set; } | |||||
} | |||||
} |
@@ -0,0 +1,7 @@ | |||||
using System; | |||||
namespace Discord.API | |||||
{ | |||||
[AttributeUsage(AttributeTargets.Property)] | |||||
public class ImageAttribute : Attribute { } | |||||
} |
@@ -0,0 +1,7 @@ | |||||
using System; | |||||
namespace Discord.API | |||||
{ | |||||
[AttributeUsage(AttributeTargets.Property)] | |||||
public class Int53Attribute : Attribute { } | |||||
} |
@@ -1,13 +1,15 @@ | |||||
using System; | using System; | ||||
using System.Diagnostics; | |||||
namespace Discord.API | namespace Discord.API | ||||
{ | { | ||||
//Based on https://github.com/dotnet/coreclr/blob/master/src/mscorlib/src/System/Nullable.cs | //Based on https://github.com/dotnet/coreclr/blob/master/src/mscorlib/src/System/Nullable.cs | ||||
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] | |||||
public struct Optional<T> : IOptional | public struct Optional<T> : IOptional | ||||
{ | { | ||||
private readonly T _value; | private readonly T _value; | ||||
/// <summary> Gets the value for this paramter, or default(T) if unspecified. </summary> | |||||
/// <summary> Gets the value for this paramter. </summary> | |||||
public T Value | public T Value | ||||
{ | { | ||||
get | get | ||||
@@ -20,8 +22,6 @@ namespace Discord.API | |||||
/// <summary> Returns true if this value has been specified. </summary> | /// <summary> Returns true if this value has been specified. </summary> | ||||
public bool IsSpecified { get; } | public bool IsSpecified { get; } | ||||
object IOptional.Value => _value; | |||||
/// <summary> Creates a new Parameter with the provided value. </summary> | /// <summary> Creates a new Parameter with the provided value. </summary> | ||||
public Optional(T value) | public Optional(T value) | ||||
{ | { | ||||
@@ -30,7 +30,7 @@ namespace Discord.API | |||||
} | } | ||||
public T GetValueOrDefault() => _value; | public T GetValueOrDefault() => _value; | ||||
public T GetValueOrDefault(T defaultValue) => IsSpecified ? _value : default(T); | |||||
public T GetValueOrDefault(T defaultValue) => IsSpecified ? _value : defaultValue; | |||||
public override bool Equals(object other) | public override bool Equals(object other) | ||||
{ | { | ||||
@@ -38,11 +38,14 @@ namespace Discord.API | |||||
if (other == null) return false; | if (other == null) return false; | ||||
return _value.Equals(other); | return _value.Equals(other); | ||||
} | } | ||||
public override int GetHashCode() => IsSpecified ? _value.GetHashCode() : 0; | public override int GetHashCode() => IsSpecified ? _value.GetHashCode() : 0; | ||||
public override string ToString() => IsSpecified ? _value.ToString() : ""; | |||||
public override string ToString() => IsSpecified ? _value?.ToString() : null; | |||||
private string DebuggerDisplay => IsSpecified ? _value.ToString() : "<unspecified>"; | |||||
public static implicit operator Optional<T>(T value) => new Optional<T>(value); | public static implicit operator Optional<T>(T value) => new Optional<T>(value); | ||||
public static implicit operator T(Optional<T> value) => value.Value; | |||||
public static explicit operator T(Optional<T> value) => value.Value; | |||||
object IOptional.Value => Value; | |||||
} | } | ||||
} | } |
@@ -1,5 +1,4 @@ | |||||
using Discord.Net.Converters; | |||||
using Newtonsoft.Json; | |||||
using Newtonsoft.Json; | |||||
using System.IO; | using System.IO; | ||||
namespace Discord.API.Rest | namespace Discord.API.Rest | ||||
@@ -11,7 +10,7 @@ namespace Discord.API.Rest | |||||
[JsonProperty("region")] | [JsonProperty("region")] | ||||
public string Region { get; set; } | public string Region { get; set; } | ||||
[JsonProperty("icon"), JsonConverter(typeof(ImageConverter))] | |||||
[JsonProperty("icon"), Image] | |||||
public Optional<Stream> Icon { get; set; } | public Optional<Stream> Icon { get; set; } | ||||
} | } | ||||
} | } |
@@ -5,8 +5,8 @@ namespace Discord.API.Rest | |||||
public class ModifyChannelPermissionsParams | public class ModifyChannelPermissionsParams | ||||
{ | { | ||||
[JsonProperty("allow")] | [JsonProperty("allow")] | ||||
public Optional<uint> Allow { get; set; } | |||||
public Optional<ulong> Allow { get; set; } | |||||
[JsonProperty("deny")] | [JsonProperty("deny")] | ||||
public Optional<uint> Deny { get; set; } | |||||
public Optional<ulong> Deny { get; set; } | |||||
} | } | ||||
} | } |
@@ -14,7 +14,7 @@ namespace Discord.API.Rest | |||||
public Optional<string> Password { get; set; } | public Optional<string> Password { get; set; } | ||||
[JsonProperty("new_password")] | [JsonProperty("new_password")] | ||||
public Optional<string> NewPassword { get; set; } | public Optional<string> NewPassword { get; set; } | ||||
[JsonProperty("avatar"), JsonConverter(typeof(ImageConverter))] | |||||
[JsonProperty("avatar"), Image] | |||||
public Optional<Stream> Avatar { get; set; } | public Optional<Stream> Avatar { get; set; } | ||||
} | } | ||||
} | } |
@@ -5,7 +5,7 @@ namespace Discord.API.Rest | |||||
public class ModifyGuildChannelsParams | public class ModifyGuildChannelsParams | ||||
{ | { | ||||
[JsonProperty("id")] | [JsonProperty("id")] | ||||
public Optional<ulong> Id { get; set; } | |||||
public ulong Id { get; set; } | |||||
[JsonProperty("position")] | [JsonProperty("position")] | ||||
public Optional<int> Position { get; set; } | public Optional<int> Position { get; set; } | ||||
} | } | ||||
@@ -16,11 +16,11 @@ namespace Discord.API.Rest | |||||
public Optional<ulong?> AFKChannelId { get; set; } | public Optional<ulong?> AFKChannelId { get; set; } | ||||
[JsonProperty("afk_timeout")] | [JsonProperty("afk_timeout")] | ||||
public Optional<int> AFKTimeout { get; set; } | public Optional<int> AFKTimeout { get; set; } | ||||
[JsonProperty("icon"), JsonConverter(typeof(ImageConverter))] | |||||
[JsonProperty("icon"), Image] | |||||
public Optional<Stream> Icon { get; set; } | public Optional<Stream> Icon { get; set; } | ||||
[JsonProperty("owner_id")] | [JsonProperty("owner_id")] | ||||
public Optional<GuildMember> Owner { get; set; } | public Optional<GuildMember> Owner { get; set; } | ||||
[JsonProperty("splash"), JsonConverter(typeof(ImageConverter))] | |||||
[JsonProperty("splash"), Image] | |||||
public Optional<Stream> Splash { get; set; } | public Optional<Stream> Splash { get; set; } | ||||
} | } | ||||
} | } |
@@ -7,7 +7,7 @@ namespace Discord.API.Rest | |||||
[JsonProperty("name")] | [JsonProperty("name")] | ||||
public Optional<string> Name { get; set; } | public Optional<string> Name { get; set; } | ||||
[JsonProperty("permissions")] | [JsonProperty("permissions")] | ||||
public Optional<uint> Permissions { get; set; } | |||||
public Optional<ulong> Permissions { get; set; } | |||||
[JsonProperty("position")] | [JsonProperty("position")] | ||||
public Optional<int> Position { get; set; } | public Optional<int> Position { get; set; } | ||||
[JsonProperty("color")] | [JsonProperty("color")] | ||||
@@ -5,6 +5,6 @@ namespace Discord.API.Rest | |||||
public class ModifyGuildRolesParams : ModifyGuildRoleParams | public class ModifyGuildRolesParams : ModifyGuildRoleParams | ||||
{ | { | ||||
[JsonProperty("id")] | [JsonProperty("id")] | ||||
public Optional<ulong> Id { get; set; } | |||||
public ulong Id { get; set; } | |||||
} | } | ||||
} | } |
@@ -6,5 +6,7 @@ namespace Discord.API.Rest | |||||
{ | { | ||||
[JsonProperty("bitrate")] | [JsonProperty("bitrate")] | ||||
public Optional<int> Bitrate { get; set; } | public Optional<int> Bitrate { get; set; } | ||||
[JsonProperty("user_limit")] | |||||
public Optional<int> UserLimit { get; set; } | |||||
} | } | ||||
} | } |
@@ -0,0 +1,18 @@ | |||||
namespace Discord.API.Gateway | |||||
{ | |||||
public enum VoiceOpCodes : byte | |||||
{ | |||||
/// <summary> C→S - Used to associate a connection with a token. </summary> | |||||
Identify = 0, | |||||
/// <summary> C→S - Used to specify configuration. </summary> | |||||
SelectProtocol = 1, | |||||
/// <summary> C←S - Used to notify that the voice connection was successful and informs the client of available protocols. </summary> | |||||
Ready = 2, | |||||
/// <summary> C↔S - Used to keep the connection alive and measure latency. </summary> | |||||
Heartbeat = 3, | |||||
/// <summary> C←S - Used to provide an encryption key to the client. </summary> | |||||
SessionDescription = 4, | |||||
/// <summary> C↔S - Used to inform that a certain user is speaking. </summary> | |||||
Speaking = 5 | |||||
} | |||||
} |
@@ -0,0 +1,16 @@ | |||||
using Newtonsoft.Json; | |||||
namespace Discord.API | |||||
{ | |||||
public class WebSocketMessage | |||||
{ | |||||
[JsonProperty("op")] | |||||
public int Operation { get; set; } | |||||
[JsonProperty("t", NullValueHandling = NullValueHandling.Ignore)] | |||||
public string Type { get; set; } | |||||
[JsonProperty("s", NullValueHandling = NullValueHandling.Ignore)] | |||||
public uint? Sequence { get; set; } | |||||
[JsonProperty("d")] | |||||
public object Payload { get; set; } | |||||
} | |||||
} |
@@ -1,7 +0,0 @@ | |||||
namespace Discord | |||||
{ | |||||
public interface IIntegrationAccount : IEntity<string> | |||||
{ | |||||
string Name { get; } | |||||
} | |||||
} |
@@ -1,10 +0,0 @@ | |||||
namespace Discord | |||||
{ | |||||
public interface IPublicInvite : IInvite | |||||
{ | |||||
/// <summary> Gets the name of the the channel this invite is linked to. </summary> | |||||
string ChannelName { get; } | |||||
/// <summary> Gets the name of the guild this invite is linked to. </summary> | |||||
string GuildName { get; } | |||||
} | |||||
} |
@@ -1,136 +0,0 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
namespace Discord | |||||
{ | |||||
public struct ChannelPermissions | |||||
{ | |||||
private static ChannelPermissions _allDM { get; } = new ChannelPermissions(0b000100_000000_0011111111_0000011001); | |||||
private static ChannelPermissions _allText { get; } = new ChannelPermissions(0b000000_000000_0001110011_0000000000); | |||||
private static ChannelPermissions _allVoice { get; } = new ChannelPermissions(0b000100_111111_0000000000_0000011001); | |||||
/// <summary> Gets a blank ChannelPermissions that grants no permissions. </summary> | |||||
public static ChannelPermissions None { get; } = new ChannelPermissions(); | |||||
/// <summary> Gets a ChannelPermissions that grants all permissions for a given channelType. </summary> | |||||
public static ChannelPermissions All(IChannel channel) | |||||
{ | |||||
switch (channel) | |||||
{ | |||||
case ITextChannel _: return _allText; | |||||
case IVoiceChannel _: return _allVoice; | |||||
case IDMChannel _: return _allDM; | |||||
default: | |||||
throw new ArgumentException("Unknown channel type", nameof(channel)); | |||||
} | |||||
} | |||||
/// <summary> Gets a packed value representing all the permissions in this ChannelPermissions. </summary> | |||||
public uint RawValue { get; } | |||||
/// <summary> If True, a user may create invites. </summary> | |||||
public bool CreateInstantInvite => PermissionUtilities.GetValue(RawValue, ChannelPermission.CreateInstantInvite); | |||||
/// <summary> If True, a user may create, delete and modify this channel. </summary> | |||||
public bool ManageChannel => PermissionUtilities.GetValue(RawValue, ChannelPermission.ManageChannel); | |||||
/// <summary> If True, a user may join channels. </summary> | |||||
public bool ReadMessages => PermissionUtilities.GetValue(RawValue, ChannelPermission.ReadMessages); | |||||
/// <summary> If True, a user may send messages. </summary> | |||||
public bool SendMessages => PermissionUtilities.GetValue(RawValue, ChannelPermission.SendMessages); | |||||
/// <summary> If True, a user may send text-to-speech messages. </summary> | |||||
public bool SendTTSMessages => PermissionUtilities.GetValue(RawValue, ChannelPermission.SendTTSMessages); | |||||
/// <summary> If True, a user may delete messages. </summary> | |||||
public bool ManageMessages => PermissionUtilities.GetValue(RawValue, ChannelPermission.ManageMessages); | |||||
/// <summary> If True, Discord will auto-embed links sent by this user. </summary> | |||||
public bool EmbedLinks => PermissionUtilities.GetValue(RawValue, ChannelPermission.EmbedLinks); | |||||
/// <summary> If True, a user may send files. </summary> | |||||
public bool AttachFiles => PermissionUtilities.GetValue(RawValue, ChannelPermission.AttachFiles); | |||||
/// <summary> If True, a user may read previous messages. </summary> | |||||
public bool ReadMessageHistory => PermissionUtilities.GetValue(RawValue, ChannelPermission.ReadMessageHistory); | |||||
/// <summary> If True, a user may mention @everyone. </summary> | |||||
public bool MentionEveryone => PermissionUtilities.GetValue(RawValue, ChannelPermission.MentionEveryone); | |||||
/// <summary> If True, a user may connect to a voice channel. </summary> | |||||
public bool Connect => PermissionUtilities.GetValue(RawValue, ChannelPermission.Connect); | |||||
/// <summary> If True, a user may speak in a voice channel. </summary> | |||||
public bool Speak => PermissionUtilities.GetValue(RawValue, ChannelPermission.Speak); | |||||
/// <summary> If True, a user may mute users. </summary> | |||||
public bool MuteMembers => PermissionUtilities.GetValue(RawValue, ChannelPermission.MuteMembers); | |||||
/// <summary> If True, a user may deafen users. </summary> | |||||
public bool DeafenMembers => PermissionUtilities.GetValue(RawValue, ChannelPermission.DeafenMembers); | |||||
/// <summary> If True, a user may move other users between voice channels. </summary> | |||||
public bool MoveMembers => PermissionUtilities.GetValue(RawValue, ChannelPermission.MoveMembers); | |||||
/// <summary> If True, a user may use voice-activity-detection rather than push-to-talk. </summary> | |||||
public bool UseVAD => PermissionUtilities.GetValue(RawValue, ChannelPermission.UseVAD); | |||||
/// <summary> If True, a user may adjust permissions. This also implictly grants all other permissions. </summary> | |||||
public bool ManagePermissions => PermissionUtilities.GetValue(RawValue, ChannelPermission.ManagePermissions); | |||||
/// <summary> Creates a new ChannelPermissions with the provided packed value. </summary> | |||||
public ChannelPermissions(uint rawValue) { RawValue = rawValue; } | |||||
private ChannelPermissions(uint initialValue, bool? createInstantInvite = null, bool? manageChannel = null, | |||||
bool? readMessages = null, bool? sendMessages = null, bool? sendTTSMessages = null, bool? manageMessages = null, | |||||
bool? embedLinks = null, bool? attachFiles = null, bool? readMessageHistory = null, bool? mentionEveryone = null, | |||||
bool? connect = null, bool? speak = null, bool? muteMembers = null, bool? deafenMembers = null, | |||||
bool? moveMembers = null, bool? useVoiceActivation = null, bool? managePermissions = null) | |||||
{ | |||||
uint value = initialValue; | |||||
PermissionUtilities.SetValue(ref value, createInstantInvite, ChannelPermission.CreateInstantInvite); | |||||
PermissionUtilities.SetValue(ref value, manageChannel, ChannelPermission.ManageChannel); | |||||
PermissionUtilities.SetValue(ref value, readMessages, ChannelPermission.ReadMessages); | |||||
PermissionUtilities.SetValue(ref value, sendMessages, ChannelPermission.SendMessages); | |||||
PermissionUtilities.SetValue(ref value, sendTTSMessages, ChannelPermission.SendTTSMessages); | |||||
PermissionUtilities.SetValue(ref value, manageMessages, ChannelPermission.ManageMessages); | |||||
PermissionUtilities.SetValue(ref value, embedLinks, ChannelPermission.EmbedLinks); | |||||
PermissionUtilities.SetValue(ref value, attachFiles, ChannelPermission.AttachFiles); | |||||
PermissionUtilities.SetValue(ref value, readMessageHistory, ChannelPermission.ReadMessageHistory); | |||||
PermissionUtilities.SetValue(ref value, mentionEveryone, ChannelPermission.MentionEveryone); | |||||
PermissionUtilities.SetValue(ref value, connect, ChannelPermission.Connect); | |||||
PermissionUtilities.SetValue(ref value, speak, ChannelPermission.Speak); | |||||
PermissionUtilities.SetValue(ref value, muteMembers, ChannelPermission.MuteMembers); | |||||
PermissionUtilities.SetValue(ref value, deafenMembers, ChannelPermission.DeafenMembers); | |||||
PermissionUtilities.SetValue(ref value, moveMembers, ChannelPermission.MoveMembers); | |||||
PermissionUtilities.SetValue(ref value, useVoiceActivation, ChannelPermission.UseVAD); | |||||
PermissionUtilities.SetValue(ref value, managePermissions, ChannelPermission.ManagePermissions); | |||||
RawValue = value; | |||||
} | |||||
/// <summary> Creates a new ChannelPermissions with the provided permissions. </summary> | |||||
public ChannelPermissions(bool createInstantInvite = false, bool manageChannel = false, | |||||
bool readMessages = false, bool sendMessages = false, bool sendTTSMessages = false, bool manageMessages = false, | |||||
bool embedLinks = false, bool attachFiles = false, bool readMessageHistory = false, bool mentionEveryone = false, | |||||
bool connect = false, bool speak = false, bool muteMembers = false, bool deafenMembers = false, | |||||
bool moveMembers = false, bool useVoiceActivation = false, bool managePermissions = false) | |||||
: this(0, createInstantInvite, manageChannel, readMessages, sendMessages, sendTTSMessages, manageMessages, | |||||
embedLinks, attachFiles, readMessageHistory, mentionEveryone, connect, speak, muteMembers, deafenMembers, | |||||
moveMembers, useVoiceActivation, managePermissions) { } | |||||
/// <summary> Creates a new ChannelPermissions from this one, changing the provided non-null permissions. </summary> | |||||
public ChannelPermissions Modify(bool? createInstantInvite = null, bool? manageChannel = null, | |||||
bool? readMessages = null, bool? sendMessages = null, bool? sendTTSMessages = null, bool? manageMessages = null, | |||||
bool? embedLinks = null, bool? attachFiles = null, bool? readMessageHistory = null, bool? mentionEveryone = null, | |||||
bool? connect = null, bool? speak = null, bool? muteMembers = null, bool? deafenMembers = null, | |||||
bool? moveMembers = null, bool? useVoiceActivation = null, bool? managePermissions = null) | |||||
=> new ChannelPermissions(RawValue, createInstantInvite, manageChannel, readMessages, sendMessages, sendTTSMessages, manageMessages, | |||||
embedLinks, attachFiles, readMessageHistory, mentionEveryone, connect, speak, muteMembers, deafenMembers, | |||||
moveMembers, useVoiceActivation, managePermissions); | |||||
/// <inheritdoc /> | |||||
public override string ToString() | |||||
{ | |||||
var perms = new List<string>(); | |||||
int x = 1; | |||||
for (byte i = 0; i < 32; i++, x <<= 1) | |||||
{ | |||||
if ((RawValue & x) != 0) | |||||
{ | |||||
if (Enum.IsDefined(typeof(ChannelPermission), i)) | |||||
perms.Add($"{(ChannelPermission)i}"); | |||||
} | |||||
} | |||||
return string.Join(", ", perms); | |||||
} | |||||
} | |||||
} |
@@ -1,87 +0,0 @@ | |||||
using System.Runtime.CompilerServices; | |||||
namespace Discord | |||||
{ | |||||
internal static class PermissionUtilities | |||||
{ | |||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||||
public static PermValue GetValue(uint allow, uint deny, ChannelPermission bit) | |||||
=> GetValue(allow, deny, (byte)bit); | |||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||||
public static PermValue GetValue(uint allow, uint deny, GuildPermission bit) | |||||
=> GetValue(allow, deny, (byte)bit); | |||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||||
public static PermValue GetValue(uint allow, uint deny, byte bit) | |||||
{ | |||||
if (HasBit(allow, bit)) | |||||
return PermValue.Allow; | |||||
else if (HasBit(deny, bit)) | |||||
return PermValue.Deny; | |||||
else | |||||
return PermValue.Inherit; | |||||
} | |||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||||
public static bool GetValue(uint value, ChannelPermission bit) | |||||
=> GetValue(value, (byte)bit); | |||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||||
public static bool GetValue(uint value, GuildPermission bit) | |||||
=> GetValue(value, (byte)bit); | |||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||||
public static bool GetValue(uint value, byte bit) => HasBit(value, bit); | |||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||||
public static void SetValue(ref uint rawValue, bool? value, ChannelPermission bit) | |||||
=> SetValue(ref rawValue, value, (byte)bit); | |||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||||
public static void SetValue(ref uint rawValue, bool? value, GuildPermission bit) | |||||
=> SetValue(ref rawValue, value, (byte)bit); | |||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||||
public static void SetValue(ref uint rawValue, bool? value, byte bit) | |||||
{ | |||||
if (value.HasValue) | |||||
{ | |||||
if (value == true) | |||||
SetBit(ref rawValue, bit); | |||||
else | |||||
UnsetBit(ref rawValue, bit); | |||||
} | |||||
} | |||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||||
public static void SetValue(ref uint allow, ref uint deny, PermValue? value, ChannelPermission bit) | |||||
=> SetValue(ref allow, ref deny, value, (byte)bit); | |||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||||
public static void SetValue(ref uint allow, ref uint deny, PermValue? value, GuildPermission bit) | |||||
=> SetValue(ref allow, ref deny, value, (byte)bit); | |||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||||
public static void SetValue(ref uint allow, ref uint deny, PermValue? value, byte bit) | |||||
{ | |||||
if (value.HasValue) | |||||
{ | |||||
switch (value) | |||||
{ | |||||
case PermValue.Allow: | |||||
SetBit(ref allow, bit); | |||||
UnsetBit(ref deny, bit); | |||||
break; | |||||
case PermValue.Deny: | |||||
UnsetBit(ref allow, bit); | |||||
SetBit(ref deny, bit); | |||||
break; | |||||
default: | |||||
UnsetBit(ref allow, bit); | |||||
UnsetBit(ref deny, bit); | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||||
private static bool HasBit(uint value, byte bit) => (value & (1U << bit)) != 0; | |||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||||
public static void SetBit(ref uint value, byte bit) => value |= (1U << bit); | |||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||||
public static void UnsetBit(ref uint value, byte bit) => value &= ~(1U << bit); | |||||
} | |||||
} |
@@ -1,8 +0,0 @@ | |||||
namespace Discord | |||||
{ | |||||
public interface IDMUser : IUser | |||||
{ | |||||
/// <summary> Gets the private channel with this user. </summary> | |||||
IDMChannel Channel { get; } | |||||
} | |||||
} |
@@ -1,20 +0,0 @@ | |||||
using System; | |||||
namespace Discord.Net.Rest | |||||
{ | |||||
public class SentRequestEventArgs : EventArgs | |||||
{ | |||||
public string Method { get; } | |||||
public string Endpoint { get; } | |||||
public int ResponseLength { get; } | |||||
public double Milliseconds { get; } | |||||
public SentRequestEventArgs(string method, string endpoint, int responseLength, double milliseconds) | |||||
{ | |||||
Method = method; | |||||
Endpoint = endpoint; | |||||
ResponseLength = responseLength; | |||||
Milliseconds = milliseconds; | |||||
} | |||||
} | |||||
} |
@@ -1,13 +0,0 @@ | |||||
using System; | |||||
namespace Discord | |||||
{ | |||||
internal static class EventExtensions | |||||
{ | |||||
public static void Raise(this EventHandler eventHandler, object sender) | |||||
=> eventHandler?.Invoke(sender, EventArgs.Empty); | |||||
public static void Raise<T>(this EventHandler<T> eventHandler, object sender, T eventArgs) | |||||
where T : EventArgs | |||||
=> eventHandler?.Invoke(sender, eventArgs); | |||||
} | |||||
} |
@@ -1,64 +0,0 @@ | |||||
namespace Discord | |||||
{ | |||||
public static class PermissionHelper | |||||
{ | |||||
public static uint Resolve(IGuildUser user) | |||||
{ | |||||
var roles = user.Roles; | |||||
uint newPermissions = 0; | |||||
for (int i = 0; i < roles.Count; i++) | |||||
newPermissions |= roles[i].Permissions.RawValue; | |||||
return newPermissions; | |||||
} | |||||
public static uint Resolve(IGuildUser user, IGuildChannel channel) | |||||
{ | |||||
uint resolvedPermissions = 0; | |||||
uint mask = ChannelPermissions.All(channel).RawValue; | |||||
if (user.Id == user.Guild.OwnerId || PermissionUtilities.GetValue(resolvedPermissions, GuildPermission.Administrator)) | |||||
resolvedPermissions = mask; //Owners and administrators always have all permissions | |||||
else | |||||
{ | |||||
//Start with this user's guild permissions | |||||
resolvedPermissions = Resolve(user); | |||||
var overwrites = channel.PermissionOverwrites; | |||||
Overwrite entry; | |||||
var roles = user.Roles; | |||||
if (roles.Count > 0) | |||||
{ | |||||
for (int i = 0; i < roles.Count; i++) | |||||
{ | |||||
if (overwrites.TryGetValue(roles[i].Id, out entry)) | |||||
resolvedPermissions &= ~entry.Permissions.DenyValue; | |||||
} | |||||
for (int i = 0; i < roles.Count; i++) | |||||
{ | |||||
if (overwrites.TryGetValue(roles[i].Id, out entry)) | |||||
resolvedPermissions |= entry.Permissions.AllowValue; | |||||
} | |||||
} | |||||
if (overwrites.TryGetValue(user.Id, out entry)) | |||||
resolvedPermissions = (resolvedPermissions & ~entry.Permissions.DenyValue) | entry.Permissions.AllowValue; | |||||
switch (channel) | |||||
{ | |||||
case ITextChannel _: | |||||
if (!PermissionUtilities.GetValue(resolvedPermissions, ChannelPermission.ReadMessages)) | |||||
resolvedPermissions = 0; //No read permission on a text channel removes all other permissions | |||||
break; | |||||
case IVoiceChannel _: | |||||
if (!PermissionUtilities.GetValue(resolvedPermissions, ChannelPermission.Connect)) | |||||
resolvedPermissions = 0; //No read permission on a text channel removes all other permissions | |||||
break; | |||||
default: | |||||
resolvedPermissions &= mask; //Ensure we didnt get any permissions this channel doesnt support (from guildPerms, for example) | |||||
break; | |||||
} | |||||
} | |||||
return resolvedPermissions; | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,475 @@ | |||||
using System; | |||||
using System.Collections; | |||||
using System.Collections.Generic; | |||||
using System.Collections.ObjectModel; | |||||
using System.Diagnostics; | |||||
using System.Threading; | |||||
namespace Discord | |||||
{ | |||||
//Based on https://github.com/dotnet/corefx/blob/master/src/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentDictionary.cs | |||||
//Copyright (c) .NET Foundation and Contributors | |||||
[DebuggerDisplay("Count = {Count}")] | |||||
internal class ConcurrentHashSet<T> : IEnumerable<T> | |||||
{ | |||||
private sealed class Tables | |||||
{ | |||||
internal readonly Node[] _buckets; | |||||
internal readonly object[] _locks; | |||||
internal volatile int[] _countPerLock; | |||||
internal Tables(Node[] buckets, object[] locks, int[] countPerLock) | |||||
{ | |||||
_buckets = buckets; | |||||
_locks = locks; | |||||
_countPerLock = countPerLock; | |||||
} | |||||
} | |||||
private sealed class Node | |||||
{ | |||||
internal readonly T _value; | |||||
internal volatile Node _next; | |||||
internal readonly int _hashcode; | |||||
internal Node(T key, int hashcode, Node next) | |||||
{ | |||||
_value = key; | |||||
_next = next; | |||||
_hashcode = hashcode; | |||||
} | |||||
} | |||||
private const int DefaultCapacity = 31; | |||||
private const int MaxLockNumber = 1024; | |||||
private static int GetBucket(int hashcode, int bucketCount) | |||||
{ | |||||
int bucketNo = (hashcode & 0x7fffffff) % bucketCount; | |||||
return bucketNo; | |||||
} | |||||
private static void GetBucketAndLockNo(int hashcode, out int bucketNo, out int lockNo, int bucketCount, int lockCount) | |||||
{ | |||||
bucketNo = (hashcode & 0x7fffffff) % bucketCount; | |||||
lockNo = bucketNo % lockCount; | |||||
} | |||||
private static int DefaultConcurrencyLevel => PlatformHelper.ProcessorCount; | |||||
private volatile Tables _tables; | |||||
private readonly IEqualityComparer<T> _comparer; | |||||
private readonly bool _growLockArray; | |||||
private int _budget; | |||||
public int Count | |||||
{ | |||||
get | |||||
{ | |||||
int count = 0; | |||||
int acquiredLocks = 0; | |||||
try | |||||
{ | |||||
AcquireAllLocks(ref acquiredLocks); | |||||
for (int i = 0; i < _tables._countPerLock.Length; i++) | |||||
count += _tables._countPerLock[i]; | |||||
} | |||||
finally { ReleaseLocks(0, acquiredLocks); } | |||||
return count; | |||||
} | |||||
} | |||||
public bool IsEmpty | |||||
{ | |||||
get | |||||
{ | |||||
int acquiredLocks = 0; | |||||
try | |||||
{ | |||||
// Acquire all locks | |||||
AcquireAllLocks(ref acquiredLocks); | |||||
for (int i = 0; i < _tables._countPerLock.Length; i++) | |||||
{ | |||||
if (_tables._countPerLock[i] != 0) | |||||
return false; | |||||
} | |||||
} | |||||
finally { ReleaseLocks(0, acquiredLocks); } | |||||
return true; | |||||
} | |||||
} | |||||
public ReadOnlyCollection<T> Values | |||||
{ | |||||
get | |||||
{ | |||||
int locksAcquired = 0; | |||||
try | |||||
{ | |||||
AcquireAllLocks(ref locksAcquired); | |||||
List<T> values = new List<T>(); | |||||
for (int i = 0; i < _tables._buckets.Length; i++) | |||||
{ | |||||
Node current = _tables._buckets[i]; | |||||
while (current != null) | |||||
{ | |||||
values.Add(current._value); | |||||
current = current._next; | |||||
} | |||||
} | |||||
return new ReadOnlyCollection<T>(values); | |||||
} | |||||
finally { ReleaseLocks(0, locksAcquired); } | |||||
} | |||||
} | |||||
public ConcurrentHashSet() | |||||
: this(DefaultConcurrencyLevel, DefaultCapacity, true, EqualityComparer<T>.Default) { } | |||||
public ConcurrentHashSet(int concurrencyLevel, int capacity) | |||||
: this(concurrencyLevel, capacity, false, EqualityComparer<T>.Default) { } | |||||
public ConcurrentHashSet(IEnumerable<T> collection) | |||||
: this(collection, EqualityComparer<T>.Default) { } | |||||
public ConcurrentHashSet(IEqualityComparer<T> comparer) | |||||
: this(DefaultConcurrencyLevel, DefaultCapacity, true, comparer) { } | |||||
public ConcurrentHashSet(IEnumerable<T> collection, IEqualityComparer<T> comparer) | |||||
: this(comparer) | |||||
{ | |||||
if (collection == null) throw new ArgumentNullException(nameof(collection)); | |||||
InitializeFromCollection(collection); | |||||
} | |||||
public ConcurrentHashSet(int concurrencyLevel, IEnumerable<T> collection, IEqualityComparer<T> comparer) | |||||
: this(concurrencyLevel, DefaultCapacity, false, comparer) | |||||
{ | |||||
if (collection == null) throw new ArgumentNullException(nameof(collection)); | |||||
if (comparer == null) throw new ArgumentNullException(nameof(comparer)); | |||||
InitializeFromCollection(collection); | |||||
} | |||||
public ConcurrentHashSet(int concurrencyLevel, int capacity, IEqualityComparer<T> comparer) | |||||
: this(concurrencyLevel, capacity, false, comparer) { } | |||||
internal ConcurrentHashSet(int concurrencyLevel, int capacity, bool growLockArray, IEqualityComparer<T> comparer) | |||||
{ | |||||
if (concurrencyLevel < 1) throw new ArgumentOutOfRangeException(nameof(concurrencyLevel)); | |||||
if (capacity < 0) throw new ArgumentOutOfRangeException(nameof(capacity)); | |||||
if (comparer == null) throw new ArgumentNullException(nameof(comparer)); | |||||
if (capacity < concurrencyLevel) | |||||
capacity = concurrencyLevel; | |||||
object[] locks = new object[concurrencyLevel]; | |||||
for (int i = 0; i < locks.Length; i++) | |||||
locks[i] = new object(); | |||||
int[] countPerLock = new int[locks.Length]; | |||||
Node[] buckets = new Node[capacity]; | |||||
_tables = new Tables(buckets, locks, countPerLock); | |||||
_comparer = comparer; | |||||
_growLockArray = growLockArray; | |||||
_budget = buckets.Length / locks.Length; | |||||
} | |||||
private void InitializeFromCollection(IEnumerable<T> collection) | |||||
{ | |||||
foreach (var value in collection) | |||||
{ | |||||
if (value == null) throw new ArgumentNullException("key"); | |||||
if (!TryAddInternal(value, _comparer.GetHashCode(value), false)) | |||||
throw new ArgumentException(); | |||||
} | |||||
if (_budget == 0) | |||||
_budget = _tables._buckets.Length / _tables._locks.Length; | |||||
} | |||||
public bool ContainsKey(T value) | |||||
{ | |||||
if (value == null) throw new ArgumentNullException("key"); | |||||
return ContainsKeyInternal(value, _comparer.GetHashCode(value)); | |||||
} | |||||
private bool ContainsKeyInternal(T value, int hashcode) | |||||
{ | |||||
Tables tables = _tables; | |||||
int bucketNo = GetBucket(hashcode, tables._buckets.Length); | |||||
Node n = Volatile.Read(ref tables._buckets[bucketNo]); | |||||
while (n != null) | |||||
{ | |||||
if (hashcode == n._hashcode && _comparer.Equals(n._value, value)) | |||||
return true; | |||||
n = n._next; | |||||
} | |||||
return false; | |||||
} | |||||
public bool TryAdd(T value) | |||||
{ | |||||
if (value == null) throw new ArgumentNullException("key"); | |||||
return TryAddInternal(value, _comparer.GetHashCode(value), true); | |||||
} | |||||
private bool TryAddInternal(T value, int hashcode, bool acquireLock) | |||||
{ | |||||
while (true) | |||||
{ | |||||
int bucketNo, lockNo; | |||||
Tables tables = _tables; | |||||
GetBucketAndLockNo(hashcode, out bucketNo, out lockNo, tables._buckets.Length, tables._locks.Length); | |||||
bool resizeDesired = false; | |||||
bool lockTaken = false; | |||||
try | |||||
{ | |||||
if (acquireLock) | |||||
Monitor.Enter(tables._locks[lockNo], ref lockTaken); | |||||
if (tables != _tables) | |||||
continue; | |||||
Node prev = null; | |||||
for (Node node = tables._buckets[bucketNo]; node != null; node = node._next) | |||||
{ | |||||
if (hashcode == node._hashcode && _comparer.Equals(node._value, value)) | |||||
return false; | |||||
prev = node; | |||||
} | |||||
Volatile.Write(ref tables._buckets[bucketNo], new Node(value, hashcode, tables._buckets[bucketNo])); | |||||
checked { tables._countPerLock[lockNo]++; } | |||||
if (tables._countPerLock[lockNo] > _budget) | |||||
resizeDesired = true; | |||||
} | |||||
finally | |||||
{ | |||||
if (lockTaken) | |||||
Monitor.Exit(tables._locks[lockNo]); | |||||
} | |||||
if (resizeDesired) | |||||
GrowTable(tables); | |||||
return true; | |||||
} | |||||
} | |||||
public bool TryRemove(T value) | |||||
{ | |||||
if (value == null) throw new ArgumentNullException("key"); | |||||
return TryRemoveInternal(value); | |||||
} | |||||
private bool TryRemoveInternal(T value) | |||||
{ | |||||
int hashcode = _comparer.GetHashCode(value); | |||||
while (true) | |||||
{ | |||||
Tables tables = _tables; | |||||
int bucketNo, lockNo; | |||||
GetBucketAndLockNo(hashcode, out bucketNo, out lockNo, tables._buckets.Length, tables._locks.Length); | |||||
lock (tables._locks[lockNo]) | |||||
{ | |||||
if (tables != _tables) | |||||
continue; | |||||
Node prev = null; | |||||
for (Node curr = tables._buckets[bucketNo]; curr != null; curr = curr._next) | |||||
{ | |||||
if (hashcode == curr._hashcode && _comparer.Equals(curr._value, value)) | |||||
{ | |||||
if (prev == null) | |||||
Volatile.Write(ref tables._buckets[bucketNo], curr._next); | |||||
else | |||||
prev._next = curr._next; | |||||
value = curr._value; | |||||
tables._countPerLock[lockNo]--; | |||||
return true; | |||||
} | |||||
prev = curr; | |||||
} | |||||
} | |||||
value = default(T); | |||||
return false; | |||||
} | |||||
} | |||||
public void Clear() | |||||
{ | |||||
int locksAcquired = 0; | |||||
try | |||||
{ | |||||
AcquireAllLocks(ref locksAcquired); | |||||
Tables newTables = new Tables(new Node[DefaultCapacity], _tables._locks, new int[_tables._countPerLock.Length]); | |||||
_tables = newTables; | |||||
_budget = Math.Max(1, newTables._buckets.Length / newTables._locks.Length); | |||||
} | |||||
finally | |||||
{ | |||||
ReleaseLocks(0, locksAcquired); | |||||
} | |||||
} | |||||
public IEnumerator<T> GetEnumerator() | |||||
{ | |||||
Node[] buckets = _tables._buckets; | |||||
for (int i = 0; i < buckets.Length; i++) | |||||
{ | |||||
Node current = Volatile.Read(ref buckets[i]); | |||||
while (current != null) | |||||
{ | |||||
yield return current._value; | |||||
current = current._next; | |||||
} | |||||
} | |||||
} | |||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); | |||||
private void GrowTable(Tables tables) | |||||
{ | |||||
const int MaxArrayLength = 0X7FEFFFFF; | |||||
int locksAcquired = 0; | |||||
try | |||||
{ | |||||
AcquireLocks(0, 1, ref locksAcquired); | |||||
if (tables != _tables) | |||||
return; | |||||
long approxCount = 0; | |||||
for (int i = 0; i < tables._countPerLock.Length; i++) | |||||
approxCount += tables._countPerLock[i]; | |||||
if (approxCount < tables._buckets.Length / 4) | |||||
{ | |||||
_budget = 2 * _budget; | |||||
if (_budget < 0) | |||||
_budget = int.MaxValue; | |||||
return; | |||||
} | |||||
int newLength = 0; | |||||
bool maximizeTableSize = false; | |||||
try | |||||
{ | |||||
checked | |||||
{ | |||||
newLength = tables._buckets.Length * 2 + 1; | |||||
while (newLength % 3 == 0 || newLength % 5 == 0 || newLength % 7 == 0) | |||||
newLength += 2; | |||||
if (newLength > MaxArrayLength) | |||||
maximizeTableSize = true; | |||||
} | |||||
} | |||||
catch (OverflowException) | |||||
{ | |||||
maximizeTableSize = true; | |||||
} | |||||
if (maximizeTableSize) | |||||
{ | |||||
newLength = MaxArrayLength; | |||||
_budget = int.MaxValue; | |||||
} | |||||
AcquireLocks(1, tables._locks.Length, ref locksAcquired); | |||||
object[] newLocks = tables._locks; | |||||
if (_growLockArray && tables._locks.Length < MaxLockNumber) | |||||
{ | |||||
newLocks = new object[tables._locks.Length * 2]; | |||||
Array.Copy(tables._locks, 0, newLocks, 0, tables._locks.Length); | |||||
for (int i = tables._locks.Length; i < newLocks.Length; i++) | |||||
newLocks[i] = new object(); | |||||
} | |||||
Node[] newBuckets = new Node[newLength]; | |||||
int[] newCountPerLock = new int[newLocks.Length]; | |||||
for (int i = 0; i < tables._buckets.Length; i++) | |||||
{ | |||||
Node current = tables._buckets[i]; | |||||
while (current != null) | |||||
{ | |||||
Node next = current._next; | |||||
int newBucketNo, newLockNo; | |||||
GetBucketAndLockNo(current._hashcode, out newBucketNo, out newLockNo, newBuckets.Length, newLocks.Length); | |||||
newBuckets[newBucketNo] = new Node(current._value, current._hashcode, newBuckets[newBucketNo]); | |||||
checked { newCountPerLock[newLockNo]++; } | |||||
current = next; | |||||
} | |||||
} | |||||
_budget = Math.Max(1, newBuckets.Length / newLocks.Length); | |||||
_tables = new Tables(newBuckets, newLocks, newCountPerLock); | |||||
} | |||||
finally { ReleaseLocks(0, locksAcquired); } | |||||
} | |||||
private void AcquireAllLocks(ref int locksAcquired) | |||||
{ | |||||
AcquireLocks(0, 1, ref locksAcquired); | |||||
AcquireLocks(1, _tables._locks.Length, ref locksAcquired); | |||||
} | |||||
private void AcquireLocks(int fromInclusive, int toExclusive, ref int locksAcquired) | |||||
{ | |||||
object[] locks = _tables._locks; | |||||
for (int i = fromInclusive; i < toExclusive; i++) | |||||
{ | |||||
bool lockTaken = false; | |||||
try | |||||
{ | |||||
Monitor.Enter(locks[i], ref lockTaken); | |||||
} | |||||
finally | |||||
{ | |||||
if (lockTaken) | |||||
locksAcquired++; | |||||
} | |||||
} | |||||
} | |||||
private void ReleaseLocks(int fromInclusive, int toExclusive) | |||||
{ | |||||
for (int i = fromInclusive; i < toExclusive; i++) | |||||
Monitor.Exit(_tables._locks[i]); | |||||
} | |||||
} | |||||
//https://github.com/dotnet/corefx/blob/d0dc5fc099946adc1035b34a8b1f6042eddb0c75/src/System.Threading.Tasks.Parallel/src/System/Threading/PlatformHelper.cs | |||||
//Copyright (c) .NET Foundation and Contributors | |||||
internal static class PlatformHelper | |||||
{ | |||||
private const int PROCESSOR_COUNT_REFRESH_INTERVAL_MS = 30000; | |||||
private static volatile int s_processorCount; | |||||
private static volatile int s_lastProcessorCountRefreshTicks; | |||||
internal static int ProcessorCount | |||||
{ | |||||
get | |||||
{ | |||||
int now = Environment.TickCount; | |||||
if (s_processorCount == 0 || (now - s_lastProcessorCountRefreshTicks) >= PROCESSOR_COUNT_REFRESH_INTERVAL_MS) | |||||
{ | |||||
s_processorCount = Environment.ProcessorCount; | |||||
s_lastProcessorCountRefreshTicks = now; | |||||
} | |||||
return s_processorCount; | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,10 @@ | |||||
namespace Discord | |||||
{ | |||||
public enum ConnectionState : byte | |||||
{ | |||||
Disconnected, | |||||
Connecting, | |||||
Connected, | |||||
Disconnecting | |||||
} | |||||
} |
@@ -2,9 +2,10 @@ | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
internal static class DateTimeHelper | |||||
internal static class DateTimeUtils | |||||
{ | { | ||||
private const ulong EpochTicks = 621355968000000000UL; | private const ulong EpochTicks = 621355968000000000UL; | ||||
private const ulong DiscordEpochMillis = 1420070400000UL; | |||||
public static DateTime FromEpochMilliseconds(ulong value) | public static DateTime FromEpochMilliseconds(ulong value) | ||||
=> new DateTime((long)(value * TimeSpan.TicksPerMillisecond + EpochTicks), DateTimeKind.Utc); | => new DateTime((long)(value * TimeSpan.TicksPerMillisecond + EpochTicks), DateTimeKind.Utc); | ||||
@@ -12,6 +13,6 @@ namespace Discord | |||||
=> new DateTime((long)(value * TimeSpan.TicksPerSecond + EpochTicks), DateTimeKind.Utc); | => new DateTime((long)(value * TimeSpan.TicksPerSecond + EpochTicks), DateTimeKind.Utc); | ||||
public static DateTime FromSnowflake(ulong value) | public static DateTime FromSnowflake(ulong value) | ||||
=> FromEpochMilliseconds((value >> 22) + 1420070400000UL); | |||||
=> FromEpochMilliseconds((value >> 22) + DiscordEpochMillis); | |||||
} | } | ||||
} | } |
@@ -1,223 +0,0 @@ | |||||
<?xml version="1.0" encoding="utf-8"?> | |||||
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> | |||||
<PropertyGroup> | |||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | |||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> | |||||
<ProjectGuid>{18F6FE23-73F6-4CA6-BBD9-F0139DC3EE90}</ProjectGuid> | |||||
<OutputType>Library</OutputType> | |||||
<AppDesignerFolder>Properties</AppDesignerFolder> | |||||
<RootNamespace>Discord</RootNamespace> | |||||
<AssemblyName>Discord.Net</AssemblyName> | |||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion> | |||||
<FileAlignment>512</FileAlignment> | |||||
<TargetFrameworkProfile /> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> | |||||
<DebugSymbols>true</DebugSymbols> | |||||
<DebugType>full</DebugType> | |||||
<Optimize>false</Optimize> | |||||
<OutputPath>bin\Debug\</OutputPath> | |||||
<DefineConstants>TRACE;DEBUG;__DEMO__,__DEMO_EXPERIMENTAL__</DefineConstants> | |||||
<ErrorReport>prompt</ErrorReport> | |||||
<WarningLevel>4</WarningLevel> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> | |||||
<DebugType>pdbonly</DebugType> | |||||
<Optimize>true</Optimize> | |||||
<OutputPath>bin\Release\</OutputPath> | |||||
<DefineConstants>TRACE</DefineConstants> | |||||
<ErrorReport>prompt</ErrorReport> | |||||
<WarningLevel>4</WarningLevel> | |||||
</PropertyGroup> | |||||
<ItemGroup> | |||||
<Reference Include="System" /> | |||||
<Reference Include="System.Core" /> | |||||
<Reference Include="System.Xml.Linq" /> | |||||
<Reference Include="System.Data.DataSetExtensions" /> | |||||
<Reference Include="Microsoft.CSharp" /> | |||||
<Reference Include="System.Data" /> | |||||
<Reference Include="System.Net.Http" /> | |||||
<Reference Include="System.Xml" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<Compile Include="API\CDN.cs" /> | |||||
<Compile Include="API\Common\Attachment.cs" /> | |||||
<Compile Include="API\Common\Channel.cs" /> | |||||
<Compile Include="API\Common\Connection.cs" /> | |||||
<Compile Include="API\Common\Embed.cs" /> | |||||
<Compile Include="API\Common\EmbedProvider.cs" /> | |||||
<Compile Include="API\Common\EmbedThumbnail.cs" /> | |||||
<Compile Include="API\Common\Emoji.cs" /> | |||||
<Compile Include="API\Common\Guild.cs" /> | |||||
<Compile Include="API\Common\GuildEmbed.cs" /> | |||||
<Compile Include="API\Common\GuildMember.cs" /> | |||||
<Compile Include="API\Common\Integration.cs" /> | |||||
<Compile Include="API\Common\IntegrationAccount.cs" /> | |||||
<Compile Include="API\Common\Invite.cs" /> | |||||
<Compile Include="API\Common\InviteChannel.cs" /> | |||||
<Compile Include="API\Common\InviteGuild.cs" /> | |||||
<Compile Include="API\Common\InviteMetadata.cs" /> | |||||
<Compile Include="API\Common\Message.cs" /> | |||||
<Compile Include="API\Common\Overwrite.cs" /> | |||||
<Compile Include="API\Common\ReadState.cs" /> | |||||
<Compile Include="API\Common\Role.cs" /> | |||||
<Compile Include="API\Common\User.cs" /> | |||||
<Compile Include="API\Common\UserGuild.cs" /> | |||||
<Compile Include="API\Common\VoiceRegion.cs" /> | |||||
<Compile Include="API\Common\VoiceState.cs" /> | |||||
<Compile Include="API\IOptional.cs" /> | |||||
<Compile Include="API\Optional.cs" /> | |||||
<Compile Include="API\Rest\DeleteMessagesParam.cs" /> | |||||
<Compile Include="API\Rest\GetGuildMembersParams.cs" /> | |||||
<Compile Include="API\Rest\LoginParams.cs" /> | |||||
<Compile Include="API\Rest\LoginResponse.cs" /> | |||||
<Compile Include="API\Rest\ModifyCurrentUserNickParams.cs" /> | |||||
<Compile Include="API\Rest\UploadFileParams.cs" /> | |||||
<Compile Include="API\Rest\GuildPruneParams.cs" /> | |||||
<Compile Include="API\Rest\CreateChannelInviteParams.cs" /> | |||||
<Compile Include="API\Rest\CreateDMChannelParams.cs" /> | |||||
<Compile Include="API\Rest\CreateGuildParams.cs" /> | |||||
<Compile Include="API\Rest\CreateGuildBanParams.cs" /> | |||||
<Compile Include="API\Rest\CreateGuildChannelParams.cs" /> | |||||
<Compile Include="API\Rest\CreateGuildIntegrationParams.cs" /> | |||||
<Compile Include="API\Rest\CreateMessageParams.cs" /> | |||||
<Compile Include="API\Rest\GetChannelMessagesParams.cs" /> | |||||
<Compile Include="API\Rest\GetGatewayResponse.cs" /> | |||||
<Compile Include="API\Rest\GetGuildPruneCountResponse.cs" /> | |||||
<Compile Include="API\Rest\ModifyChannelPermissionsParams.cs" /> | |||||
<Compile Include="API\Rest\ModifyCurrentUserParams.cs" /> | |||||
<Compile Include="API\Rest\ModifyGuildChannelsParams.cs" /> | |||||
<Compile Include="API\Rest\ModifyGuildParams.cs" /> | |||||
<Compile Include="API\Rest\ModifyGuildChannelParams.cs" /> | |||||
<Compile Include="API\Rest\ModifyGuildEmbedParams.cs" /> | |||||
<Compile Include="API\Rest\ModifyGuildIntegrationParams.cs" /> | |||||
<Compile Include="API\Rest\ModifyGuildMemberParams.cs" /> | |||||
<Compile Include="API\Rest\ModifyGuildRolesParams.cs" /> | |||||
<Compile Include="API\Rest\ModifyGuildRoleParams.cs" /> | |||||
<Compile Include="API\Rest\ModifyMessageParams.cs" /> | |||||
<Compile Include="API\Rest\ModifyTextChannelParams.cs" /> | |||||
<Compile Include="API\Rest\ModifyVoiceChannelParams.cs" /> | |||||
<Compile Include="DiscordConfig.cs" /> | |||||
<Compile Include="API\DiscordRawClient.cs" /> | |||||
<Compile Include="Net\Converters\OptionalContractResolver.cs" /> | |||||
<Compile Include="Net\Converters\OptionalConverter.cs" /> | |||||
<Compile Include="Net\RateLimitException.cs" /> | |||||
<Compile Include="Net\Rest\RequestQueue\BucketGroup.cs" /> | |||||
<Compile Include="Net\Rest\RequestQueue\GlobalBucket.cs" /> | |||||
<Compile Include="Net\Rest\RequestQueue\GuildBucket.cs" /> | |||||
<Compile Include="Net\Rest\RequestQueue\RequestQueue.cs" /> | |||||
<Compile Include="Net\Rest\RequestQueue\RequestQueueBucket.cs" /> | |||||
<Compile Include="Net\Rest\RequestQueue\RestRequest.cs" /> | |||||
<Compile Include="Rest\DiscordClient.cs" /> | |||||
<Compile Include="Common\Entities\Guilds\IGuildEmbed.cs" /> | |||||
<Compile Include="Common\Entities\Guilds\IIntegrationAccount.cs" /> | |||||
<Compile Include="Common\Entities\Users\IConnection.cs" /> | |||||
<Compile Include="Common\Entities\Guilds\IGuildIntegration.cs" /> | |||||
<Compile Include="Common\Entities\Invites\IPublicInvite.cs" /> | |||||
<Compile Include="Common\Entities\Messages\Attachment.cs" /> | |||||
<Compile Include="Common\Entities\Channels\IChannel.cs" /> | |||||
<Compile Include="Common\Entities\Channels\IDMChannel.cs" /> | |||||
<Compile Include="Common\Entities\Channels\IGuildChannel.cs" /> | |||||
<Compile Include="Common\Entities\Channels\IMessageChannel.cs" /> | |||||
<Compile Include="Common\Entities\Channels\ITextChannel.cs" /> | |||||
<Compile Include="Common\Entities\Channels\IVoiceChannel.cs" /> | |||||
<Compile Include="Common\Entities\Channels\ChannelType.cs" /> | |||||
<Compile Include="Common\Entities\Roles\Color.cs" /> | |||||
<Compile Include="Common\Entities\Messages\Direction.cs" /> | |||||
<Compile Include="Common\Entities\Messages\Embed.cs" /> | |||||
<Compile Include="Common\Entities\Messages\EmbedProvider.cs" /> | |||||
<Compile Include="Common\Entities\Messages\EmbedThumbnail.cs" /> | |||||
<Compile Include="Common\Entities\Guilds\Emoji.cs" /> | |||||
<Compile Include="Common\Entities\Guilds\IUserGuild.cs" /> | |||||
<Compile Include="Common\Entities\IDeletable.cs" /> | |||||
<Compile Include="Common\Entities\IEntity.cs" /> | |||||
<Compile Include="Common\Entities\Guilds\IGuild.cs" /> | |||||
<Compile Include="Common\Entities\IMentionable.cs" /> | |||||
<Compile Include="Common\Entities\Messages\IMessage.cs" /> | |||||
<Compile Include="Common\Entities\Invites\IGuildInvite.cs" /> | |||||
<Compile Include="Common\Entities\Invites\IInvite.cs" /> | |||||
<Compile Include="Common\Entities\Roles\IRole.cs" /> | |||||
<Compile Include="Common\Entities\ISnowflakeEntity.cs" /> | |||||
<Compile Include="Common\Entities\IUpdateable.cs" /> | |||||
<Compile Include="Common\Entities\Guilds\IVoiceRegion.cs" /> | |||||
<Compile Include="Common\Entities\Permissions\ChannelPermission.cs" /> | |||||
<Compile Include="Common\Entities\Permissions\GuildPermission.cs" /> | |||||
<Compile Include="Common\Entities\Permissions\ChannelPermissions.cs" /> | |||||
<Compile Include="Common\Entities\Permissions\GuildPermissions.cs" /> | |||||
<Compile Include="Common\Entities\Permissions\Overwrite.cs" /> | |||||
<Compile Include="Common\Entities\Permissions\OverwritePermissions.cs" /> | |||||
<Compile Include="Common\Entities\Permissions\PermissionUtilities.cs" /> | |||||
<Compile Include="Common\Entities\Permissions\PermissionTarget.cs" /> | |||||
<Compile Include="Common\Entities\Permissions\PermValue.cs" /> | |||||
<Compile Include="Common\Entities\Users\UserStatus.cs" /> | |||||
<Compile Include="Common\Entities\Users\IDMUser.cs" /> | |||||
<Compile Include="Common\Entities\Users\IGuildUser.cs" /> | |||||
<Compile Include="Common\Entities\Users\ISelfUser.cs" /> | |||||
<Compile Include="Common\Entities\Users\IUser.cs" /> | |||||
<Compile Include="Rest\Entities\Guilds\Guild.cs" /> | |||||
<Compile Include="Rest\Entities\Channels\GuildChannel.cs" /> | |||||
<Compile Include="Rest\Entities\Channels\TextChannel.cs" /> | |||||
<Compile Include="Rest\Entities\Channels\VoiceChannel.cs" /> | |||||
<Compile Include="Rest\Entities\Guilds\GuildEmbed.cs" /> | |||||
<Compile Include="Rest\Entities\Guilds\GuildIntegration.cs" /> | |||||
<Compile Include="Rest\Entities\Guilds\IntegrationAccount.cs" /> | |||||
<Compile Include="Rest\Entities\Users\Connection.cs" /> | |||||
<Compile Include="Common\Helpers\PermissionHelper.cs" /> | |||||
<Compile Include="Rest\Entities\Invites\GuildInvite.cs" /> | |||||
<Compile Include="Rest\Entities\Invites\Invite.cs" /> | |||||
<Compile Include="Rest\Entities\Invites\PublicInvite.cs" /> | |||||
<Compile Include="Rest\Entities\Message.cs" /> | |||||
<Compile Include="Rest\Entities\Role.cs" /> | |||||
<Compile Include="Rest\Entities\Guilds\UserGuild.cs" /> | |||||
<Compile Include="Rest\Entities\Users\DMUser.cs" /> | |||||
<Compile Include="Rest\Entities\Users\GuildUser.cs" /> | |||||
<Compile Include="Rest\Entities\Users\PublicUser.cs" /> | |||||
<Compile Include="Rest\Entities\Guilds\VoiceRegion.cs" /> | |||||
<Compile Include="Common\Events\LogMessageEventArgs.cs" /> | |||||
<Compile Include="Common\Events\SentRequestEventArgs.cs" /> | |||||
<Compile Include="Common\Helpers\DateTimeHelper.cs" /> | |||||
<Compile Include="Common\Helpers\EventExtensions.cs" /> | |||||
<Compile Include="Common\Helpers\MentionHelper.cs" /> | |||||
<Compile Include="IDiscordClient.cs" /> | |||||
<Compile Include="Logging\ILogger.cs" /> | |||||
<Compile Include="Logging\Logger.cs" /> | |||||
<Compile Include="Logging\LogManager.cs" /> | |||||
<Compile Include="LogSeverity.cs" /> | |||||
<Compile Include="Net\Converters\ChannelTypeConverter.cs" /> | |||||
<Compile Include="Net\Converters\ImageConverter.cs" /> | |||||
<Compile Include="Net\Converters\NullableUInt64Converter.cs" /> | |||||
<Compile Include="Net\Converters\PermissionTargetConverter.cs" /> | |||||
<Compile Include="Net\Converters\StringEntityConverter.cs" /> | |||||
<Compile Include="Net\Converters\UInt64ArrayConverter.cs" /> | |||||
<Compile Include="Net\Converters\UInt64Converter.cs" /> | |||||
<Compile Include="Net\Converters\UInt64EntityConverter.cs" /> | |||||
<Compile Include="Net\Converters\UserStatusConverter.cs" /> | |||||
<Compile Include="Net\HttpException.cs" /> | |||||
<Compile Include="Net\Rest\DefaultRestClient.cs" /> | |||||
<Compile Include="Net\Rest\RequestQueue\IRequestQueue.cs" /> | |||||
<Compile Include="Net\Rest\IRestClient.cs" /> | |||||
<Compile Include="Net\Rest\MultipartFile.cs" /> | |||||
<Compile Include="Net\Rest\RestClientProvider.cs" /> | |||||
<Compile Include="Properties\AssemblyInfo.cs" /> | |||||
<Compile Include="Rest\Entities\Channels\DMChannel.cs" /> | |||||
<Compile Include="Rest\Entities\Users\SelfUser.cs" /> | |||||
<Compile Include="Rest\Entities\Users\User.cs" /> | |||||
<Compile Include="TokenType.cs" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<None Include="Common\Entities\Users\IVoiceState.cs.old" /> | |||||
<None Include="project.json" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<Folder Include="Net\WebSockets\" /> | |||||
</ItemGroup> | |||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> | |||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. | |||||
Other similar extension points exist, see Microsoft.Common.targets. | |||||
<Target Name="BeforeBuild"> | |||||
</Target> | |||||
<Target Name="AfterBuild"> | |||||
</Target> | |||||
--> | |||||
</Project> |
@@ -0,0 +1,19 @@ | |||||
<?xml version="1.0" encoding="utf-8"?> | |||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||||
<PropertyGroup> | |||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion> | |||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath> | |||||
</PropertyGroup> | |||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" /> | |||||
<PropertyGroup Label="Globals"> | |||||
<ProjectGuid>91e9e7bd-75c9-4e98-84aa-2c271922e5c2</ProjectGuid> | |||||
<RootNamespace>Discord</RootNamespace> | |||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath> | |||||
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath> | |||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion> | |||||
</PropertyGroup> | |||||
<PropertyGroup> | |||||
<SchemaVersion>2.0</SchemaVersion> | |||||
</PropertyGroup> | |||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" /> | |||||
</Project> |
@@ -3,12 +3,15 @@ using System.Reflection; | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
//TODO: Add socket config items in their own class | |||||
public class DiscordConfig | public class DiscordConfig | ||||
{ | { | ||||
public static string Version { get; } = typeof(DiscordConfig).GetTypeInfo().Assembly?.GetName().Version.ToString(3) ?? "Unknown"; | public static string Version { get; } = typeof(DiscordConfig).GetTypeInfo().Assembly?.GetName().Version.ToString(3) ?? "Unknown"; | ||||
public static string UserAgent { get; } = $"DiscordBot (https://github.com/RogueException/Discord.Net, v{Version})"; | public static string UserAgent { get; } = $"DiscordBot (https://github.com/RogueException/Discord.Net, v{Version})"; | ||||
public const int GatewayAPIVersion = 3; | |||||
public const int GatewayAPIVersion = 3; //TODO: Upgrade to 4 | |||||
public const string GatewayEncoding = "json"; | |||||
public const string ClientAPIUrl = "https://discordapp.com/api/"; | public const string ClientAPIUrl = "https://discordapp.com/api/"; | ||||
public const string CDNUrl = "https://cdn.discordapp.com/"; | public const string CDNUrl = "https://cdn.discordapp.com/"; | ||||
@@ -26,6 +29,6 @@ namespace Discord | |||||
public LogSeverity LogLevel { get; set; } = LogSeverity.Info; | public LogSeverity LogLevel { get; set; } = LogSeverity.Info; | ||||
/// <summary> Gets or sets the provider used to generate new REST connections. </summary> | /// <summary> Gets or sets the provider used to generate new REST connections. </summary> | ||||
public RestClientProvider RestClientProvider { get; set; } = (url, ct) => new DefaultRestClient(url, ct); | |||||
public RestClientProvider RestClientProvider { get; set; } = url => new DefaultRestClient(url); | |||||
} | } | ||||
} | } |
@@ -7,6 +7,8 @@ namespace Discord | |||||
{ | { | ||||
/// <summary> Gets a collection of all users in this channel. </summary> | /// <summary> Gets a collection of all users in this channel. </summary> | ||||
Task<IEnumerable<IUser>> GetUsers(); | Task<IEnumerable<IUser>> GetUsers(); | ||||
/// <summary> Gets a paginated collection of all users in this channel. </summary> | |||||
Task<IEnumerable<IUser>> GetUsers(int limit, int offset = 0); | |||||
/// <summary> Gets a user in this channel with the provided id.</summary> | /// <summary> Gets a user in this channel with the provided id.</summary> | ||||
Task<IUser> GetUser(ulong id); | Task<IUser> GetUser(ulong id); | ||||
} | } |
@@ -5,7 +5,7 @@ namespace Discord | |||||
public interface IDMChannel : IMessageChannel, IUpdateable | public interface IDMChannel : IMessageChannel, IUpdateable | ||||
{ | { | ||||
/// <summary> Gets the recipient of all messages in this channel. </summary> | /// <summary> Gets the recipient of all messages in this channel. </summary> | ||||
IDMUser Recipient { get; } | |||||
IUser Recipient { get; } | |||||
/// <summary> Closes this private channel, removing it from your channel list. </summary> | /// <summary> Closes this private channel, removing it from your channel list. </summary> | ||||
Task Close(); | Task Close(); |
@@ -20,9 +20,9 @@ namespace Discord | |||||
/// <param name="maxUses"> The max amount of times this invite may be used. Set to null to have unlimited uses. </param> | /// <param name="maxUses"> The max amount of times this invite may be used. Set to null to have unlimited uses. </param> | ||||
/// <param name="isTemporary"> If true, a user accepting this invite will be kicked from the guild after closing their client. </param> | /// <param name="isTemporary"> If true, a user accepting this invite will be kicked from the guild after closing their client. </param> | ||||
/// <param name="withXkcd"> If true, creates a human-readable link. Not supported if maxAge is set to null. </param> | /// <param name="withXkcd"> If true, creates a human-readable link. Not supported if maxAge is set to null. </param> | ||||
Task<IGuildInvite> CreateInvite(int? maxAge = 1800, int? maxUses = default(int?), bool isTemporary = false, bool withXkcd = false); | |||||
Task<IInviteMetadata> CreateInvite(int? maxAge = 1800, int? maxUses = default(int?), bool isTemporary = false, bool withXkcd = false); | |||||
/// <summary> Returns a collection of all invites to this channel. </summary> | /// <summary> Returns a collection of all invites to this channel. </summary> | ||||
Task<IEnumerable<IGuildInvite>> GetInvites(); | |||||
Task<IEnumerable<IInviteMetadata>> GetInvites(); | |||||
/// <summary> Gets a collection of permission overwrites for this channel. </summary> | /// <summary> Gets a collection of permission overwrites for this channel. </summary> | ||||
IReadOnlyDictionary<ulong, Overwrite> PermissionOverwrites { get; } | IReadOnlyDictionary<ulong, Overwrite> PermissionOverwrites { get; } |
@@ -6,8 +6,12 @@ namespace Discord | |||||
{ | { | ||||
public interface IMessageChannel : IChannel | public interface IMessageChannel : IChannel | ||||
{ | { | ||||
/// <summary> Gets the message in this message channel with the given id, or null if none was found. </summary> | |||||
Task<IMessage> GetMessage(ulong id); | |||||
/// <summary> Gets all messages in this channel's cache. </summary> | |||||
IEnumerable<IMessage> CachedMessages { get; } | |||||
/// <summary> Gets the message from this channel's cache with the given id, or null if none was found. </summary> | |||||
Task<IMessage> GetCachedMessage(ulong id); | |||||
/// <summary> Gets the last N messages from this message channel. </summary> | /// <summary> Gets the last N messages from this message channel. </summary> | ||||
Task<IEnumerable<IMessage>> GetMessages(int limit = DiscordConfig.MaxMessagesPerBatch); | Task<IEnumerable<IMessage>> GetMessages(int limit = DiscordConfig.MaxMessagesPerBatch); | ||||
/// <summary> Gets a collection of messages in this channel. </summary> | /// <summary> Gets a collection of messages in this channel. </summary> |
@@ -8,6 +8,8 @@ namespace Discord | |||||
{ | { | ||||
/// <summary> Gets the bitrate, in bits per second, clients in this voice channel are requested to use. </summary> | /// <summary> Gets the bitrate, in bits per second, clients in this voice channel are requested to use. </summary> | ||||
int Bitrate { get; } | int Bitrate { get; } | ||||
/// <summary> Gets the max amount of users allowed to be connected to this channel at one time. A value of 0 represents no limit. </summary> | |||||
int UserLimit { get; } | |||||
/// <summary> Modifies this voice channel. </summary> | /// <summary> Modifies this voice channel. </summary> | ||||
Task Modify(Action<ModifyVoiceChannelParams> func); | Task Modify(Action<ModifyVoiceChannelParams> func); |
@@ -70,13 +70,13 @@ namespace Discord | |||||
Task<IVoiceChannel> CreateVoiceChannel(string name); | Task<IVoiceChannel> CreateVoiceChannel(string name); | ||||
/// <summary> Gets a collection of all invites to this guild. </summary> | /// <summary> Gets a collection of all invites to this guild. </summary> | ||||
Task<IEnumerable<IGuildInvite>> GetInvites(); | |||||
Task<IEnumerable<IInviteMetadata>> GetInvites(); | |||||
/// <summary> Creates a new invite to this guild. </summary> | /// <summary> Creates a new invite to this guild. </summary> | ||||
/// <param name="maxAge"> The time (in seconds) until the invite expires. Set to null to never expire. </param> | /// <param name="maxAge"> The time (in seconds) until the invite expires. Set to null to never expire. </param> | ||||
/// <param name="maxUses"> The max amount of times this invite may be used. Set to null to have unlimited uses. </param> | /// <param name="maxUses"> The max amount of times this invite may be used. Set to null to have unlimited uses. </param> | ||||
/// <param name="isTemporary"> If true, a user accepting this invite will be kicked from the guild after closing their client. </param> | /// <param name="isTemporary"> If true, a user accepting this invite will be kicked from the guild after closing their client. </param> | ||||
/// <param name="withXkcd"> If true, creates a human-readable link. Not supported if maxAge is set to null. </param> | /// <param name="withXkcd"> If true, creates a human-readable link. Not supported if maxAge is set to null. </param> | ||||
Task<IGuildInvite> CreateInvite(int? maxAge = 1800, int? maxUses = default(int?), bool isTemporary = false, bool withXkcd = false); | |||||
Task<IInviteMetadata> CreateInvite(int? maxAge = 1800, int? maxUses = default(int?), bool isTemporary = false, bool withXkcd = false); | |||||
/// <summary> Gets a collection of all roles in this guild. </summary> | /// <summary> Gets a collection of all roles in this guild. </summary> | ||||
Task<IEnumerable<IRole>> GetRoles(); | Task<IEnumerable<IRole>> GetRoles(); |
@@ -12,10 +12,10 @@ namespace Discord | |||||
ulong ExpireBehavior { get; } | ulong ExpireBehavior { get; } | ||||
ulong ExpireGracePeriod { get; } | ulong ExpireGracePeriod { get; } | ||||
DateTime SyncedAt { get; } | DateTime SyncedAt { get; } | ||||
IntegrationAccount Account { get; } | |||||
IGuild Guild { get; } | IGuild Guild { get; } | ||||
IUser User { get; } | IUser User { get; } | ||||
IRole Role { get; } | IRole Role { get; } | ||||
IIntegrationAccount Account { get; } | |||||
} | } | ||||
} | } |
@@ -0,0 +1,17 @@ | |||||
using System.Diagnostics; | |||||
namespace Discord | |||||
{ | |||||
[DebuggerDisplay("{DebuggerDisplay,nq}")] | |||||
public struct IntegrationAccount | |||||
{ | |||||
/// <inheritdoc /> | |||||
public string Id { get; } | |||||
/// <inheritdoc /> | |||||
public string Name { get; private set; } | |||||
public override string ToString() => Name; | |||||
private string DebuggerDisplay => $"{Name} ({Id})"; | |||||
} | |||||
} |
@@ -1,7 +1,9 @@ | |||||
using Model = Discord.API.VoiceRegion; | |||||
using System.Diagnostics; | |||||
using Model = Discord.API.VoiceRegion; | |||||
namespace Discord.Rest | |||||
namespace Discord | |||||
{ | { | ||||
[DebuggerDisplay("{DebuggerDisplay,nq}")] | |||||
public class VoiceRegion : IVoiceRegion | public class VoiceRegion : IVoiceRegion | ||||
{ | { | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
@@ -27,6 +29,7 @@ namespace Discord.Rest | |||||
SamplePort = model.SamplePort; | SamplePort = model.SamplePort; | ||||
} | } | ||||
public override string ToString() => $"{Name ?? Id.ToString()}"; | |||||
public override string ToString() => Name; | |||||
private string DebuggerDisplay => $"{Name} ({Id}{(IsVip ? ", VIP" : "")}{(IsOptimal ? ", Optimal" : "")})"; | |||||
} | } | ||||
} | } |
@@ -2,7 +2,7 @@ | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
public interface IInvite : IEntity<string> | |||||
public interface IInvite : IEntity<string>, IDeletable | |||||
{ | { | ||||
/// <summary> Gets the unique identifier for this invite. </summary> | /// <summary> Gets the unique identifier for this invite. </summary> | ||||
string Code { get; } | string Code { get; } |
@@ -1,6 +1,6 @@ | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
public interface IGuildInvite : IDeletable, IInvite | |||||
public interface IInviteMetadata : IInvite | |||||
{ | { | ||||
/// <summary> Returns true if this invite was revoked. </summary> | /// <summary> Returns true if this invite was revoked. </summary> | ||||
bool IsRevoked { get; } | bool IsRevoked { get; } | ||||
@@ -12,8 +12,5 @@ | |||||
int? MaxUses { get; } | int? MaxUses { get; } | ||||
/// <summary> Gets the amount of times this invite has been used. </summary> | /// <summary> Gets the amount of times this invite has been used. </summary> | ||||
int Uses { get; } | int Uses { get; } | ||||
/// <summary> Gets the guild this invite is linked to. </summary> | |||||
IGuild Guild { get; } | |||||
} | } | ||||
} | } |
@@ -0,0 +1,65 @@ | |||||
using System.Diagnostics; | |||||
using System.Threading.Tasks; | |||||
using Model = Discord.API.Invite; | |||||
namespace Discord | |||||
{ | |||||
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] | |||||
public class Invite : IInvite | |||||
{ | |||||
/// <inheritdoc /> | |||||
public string Code { get; } | |||||
internal IDiscordClient Discord { get; } | |||||
/// <inheritdoc /> | |||||
public ulong GuildId { get; private set; } | |||||
/// <inheritdoc /> | |||||
public ulong ChannelId { get; private set; } | |||||
/// <inheritdoc /> | |||||
public string XkcdCode { get; private set; } | |||||
/// <inheritdoc /> | |||||
public string GuildName { get; private set; } | |||||
/// <inheritdoc /> | |||||
public string ChannelName { get; private set; } | |||||
/// <inheritdoc /> | |||||
public string Url => $"{DiscordConfig.InviteUrl}/{XkcdCode ?? Code}"; | |||||
/// <inheritdoc /> | |||||
public string XkcdUrl => XkcdCode != null ? $"{DiscordConfig.InviteUrl}/{XkcdCode}" : null; | |||||
internal Invite(IDiscordClient discord, Model model) | |||||
{ | |||||
Discord = discord; | |||||
Code = model.Code; | |||||
Update(model); | |||||
} | |||||
protected virtual void Update(Model model) | |||||
{ | |||||
XkcdCode = model.XkcdPass; | |||||
GuildId = model.Guild.Id; | |||||
ChannelId = model.Channel.Id; | |||||
GuildName = model.Guild.Name; | |||||
ChannelName = model.Channel.Name; | |||||
} | |||||
/// <inheritdoc /> | |||||
public async Task Accept() | |||||
{ | |||||
await Discord.ApiClient.AcceptInvite(Code).ConfigureAwait(false); | |||||
} | |||||
/// <inheritdoc /> | |||||
public async Task Delete() | |||||
{ | |||||
await Discord.ApiClient.DeleteInvite(Code).ConfigureAwait(false); | |||||
} | |||||
/// <inheritdoc /> | |||||
public override string ToString() => XkcdUrl ?? Url; | |||||
private string DebuggerDisplay => $"{XkcdUrl ?? Url} ({GuildName} / {ChannelName})"; | |||||
string IEntity<string>.Id => Code; | |||||
} | |||||
} |
@@ -0,0 +1,32 @@ | |||||
using Model = Discord.API.InviteMetadata; | |||||
namespace Discord | |||||
{ | |||||
public class InviteMetadata : Invite, IInviteMetadata | |||||
{ | |||||
/// <inheritdoc /> | |||||
public bool IsRevoked { get; private set; } | |||||
/// <inheritdoc /> | |||||
public bool IsTemporary { get; private set; } | |||||
/// <inheritdoc /> | |||||
public int? MaxAge { get; private set; } | |||||
/// <inheritdoc /> | |||||
public int? MaxUses { get; private set; } | |||||
/// <inheritdoc /> | |||||
public int Uses { get; private set; } | |||||
internal InviteMetadata(IDiscordClient client, Model model) | |||||
: base(client, model) | |||||
{ | |||||
Update(model); | |||||
} | |||||
private void Update(Model model) | |||||
{ | |||||
IsRevoked = model.Revoked; | |||||
IsTemporary = model.Temporary; | |||||
MaxAge = model.MaxAge != 0 ? model.MaxAge : (int?)null; | |||||
MaxUses = model.MaxUses; | |||||
Uses = model.Uses; | |||||
} | |||||
} | |||||
} |
@@ -1,7 +1,7 @@ | |||||
using System; | using System; | ||||
using System.Collections.Generic; | |||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
using Discord.API.Rest; | using Discord.API.Rest; | ||||
using System.Collections.Generic; | |||||
namespace Discord | namespace Discord | ||||
{ | { |
@@ -1,6 +1,6 @@ | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
internal enum ChannelPermission : byte | |||||
public enum ChannelPermission : byte | |||||
{ | { | ||||
//General | //General | ||||
CreateInstantInvite = 0, | CreateInstantInvite = 0, |
@@ -0,0 +1,151 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Diagnostics; | |||||
namespace Discord | |||||
{ | |||||
[DebuggerDisplay("{DebuggerDisplay,nq}")] | |||||
public struct ChannelPermissions | |||||
{ | |||||
#if CSHARP7 | |||||
private static ChannelPermissions _allDM { get; } = new ChannelPermissions(0b000100_000000_0011111111_0000011001); | |||||
private static ChannelPermissions _allText { get; } = new ChannelPermissions(0b000000_000000_0001110011_0000000000); | |||||
private static ChannelPermissions _allVoice { get; } = new ChannelPermissions(0b000100_111111_0000000000_0000011001); | |||||
#else | |||||
private static ChannelPermissions _allDM { get; } = new ChannelPermissions(Convert.ToUInt64("00010000000000111111110000011001", 2)); | |||||
private static ChannelPermissions _allText { get; } = new ChannelPermissions(Convert.ToUInt64("00000000000000011100110000000000", 2)); | |||||
private static ChannelPermissions _allVoice { get; } = new ChannelPermissions(Convert.ToUInt64("00010011111100000000000000011001", 2)); | |||||
#endif | |||||
/// <summary> Gets a blank ChannelPermissions that grants no permissions. </summary> | |||||
public static ChannelPermissions None { get; } = new ChannelPermissions(); | |||||
/// <summary> Gets a ChannelPermissions that grants all permissions for a given channelType. </summary> | |||||
public static ChannelPermissions All(IChannel channel) | |||||
{ | |||||
#if CSHARP7 | |||||
switch (channel) | |||||
{ | |||||
case ITextChannel _: return _allText; | |||||
case IVoiceChannel _: return _allVoice; | |||||
case IDMChannel _: return _allDM; | |||||
default: | |||||
throw new ArgumentException("Unknown channel type", nameof(channel)); | |||||
} | |||||
#else | |||||
if (channel is ITextChannel) return _allText; | |||||
if (channel is IVoiceChannel) return _allVoice; | |||||
if (channel is IDMChannel) return _allDM; | |||||
throw new ArgumentException("Unknown channel type", nameof(channel)); | |||||
#endif | |||||
} | |||||
/// <summary> Gets a packed value representing all the permissions in this ChannelPermissions. </summary> | |||||
public ulong RawValue { get; } | |||||
/// <summary> If True, a user may create invites. </summary> | |||||
public bool CreateInstantInvite => Permissions.GetValue(RawValue, ChannelPermission.CreateInstantInvite); | |||||
/// <summary> If True, a user may create, delete and modify this channel. </summary> | |||||
public bool ManageChannel => Permissions.GetValue(RawValue, ChannelPermission.ManageChannel); | |||||
/// <summary> If True, a user may join channels. </summary> | |||||
public bool ReadMessages => Permissions.GetValue(RawValue, ChannelPermission.ReadMessages); | |||||
/// <summary> If True, a user may send messages. </summary> | |||||
public bool SendMessages => Permissions.GetValue(RawValue, ChannelPermission.SendMessages); | |||||
/// <summary> If True, a user may send text-to-speech messages. </summary> | |||||
public bool SendTTSMessages => Permissions.GetValue(RawValue, ChannelPermission.SendTTSMessages); | |||||
/// <summary> If True, a user may delete messages. </summary> | |||||
public bool ManageMessages => Permissions.GetValue(RawValue, ChannelPermission.ManageMessages); | |||||
/// <summary> If True, Discord will auto-embed links sent by this user. </summary> | |||||
public bool EmbedLinks => Permissions.GetValue(RawValue, ChannelPermission.EmbedLinks); | |||||
/// <summary> If True, a user may send files. </summary> | |||||
public bool AttachFiles => Permissions.GetValue(RawValue, ChannelPermission.AttachFiles); | |||||
/// <summary> If True, a user may read previous messages. </summary> | |||||
public bool ReadMessageHistory => Permissions.GetValue(RawValue, ChannelPermission.ReadMessageHistory); | |||||
/// <summary> If True, a user may mention @everyone. </summary> | |||||
public bool MentionEveryone => Permissions.GetValue(RawValue, ChannelPermission.MentionEveryone); | |||||
/// <summary> If True, a user may connect to a voice channel. </summary> | |||||
public bool Connect => Permissions.GetValue(RawValue, ChannelPermission.Connect); | |||||
/// <summary> If True, a user may speak in a voice channel. </summary> | |||||
public bool Speak => Permissions.GetValue(RawValue, ChannelPermission.Speak); | |||||
/// <summary> If True, a user may mute users. </summary> | |||||
public bool MuteMembers => Permissions.GetValue(RawValue, ChannelPermission.MuteMembers); | |||||
/// <summary> If True, a user may deafen users. </summary> | |||||
public bool DeafenMembers => Permissions.GetValue(RawValue, ChannelPermission.DeafenMembers); | |||||
/// <summary> If True, a user may move other users between voice channels. </summary> | |||||
public bool MoveMembers => Permissions.GetValue(RawValue, ChannelPermission.MoveMembers); | |||||
/// <summary> If True, a user may use voice-activity-detection rather than push-to-talk. </summary> | |||||
public bool UseVAD => Permissions.GetValue(RawValue, ChannelPermission.UseVAD); | |||||
/// <summary> If True, a user may adjust permissions. This also implictly grants all other permissions. </summary> | |||||
public bool ManagePermissions => Permissions.GetValue(RawValue, ChannelPermission.ManagePermissions); | |||||
/// <summary> Creates a new ChannelPermissions with the provided packed value. </summary> | |||||
public ChannelPermissions(ulong rawValue) { RawValue = rawValue; } | |||||
private ChannelPermissions(ulong initialValue, bool? createInstantInvite = null, bool? manageChannel = null, | |||||
bool? readMessages = null, bool? sendMessages = null, bool? sendTTSMessages = null, bool? manageMessages = null, | |||||
bool? embedLinks = null, bool? attachFiles = null, bool? readMessageHistory = null, bool? mentionEveryone = null, | |||||
bool? connect = null, bool? speak = null, bool? muteMembers = null, bool? deafenMembers = null, | |||||
bool? moveMembers = null, bool? useVoiceActivation = null, bool? managePermissions = null) | |||||
{ | |||||
ulong value = initialValue; | |||||
Permissions.SetValue(ref value, createInstantInvite, ChannelPermission.CreateInstantInvite); | |||||
Permissions.SetValue(ref value, manageChannel, ChannelPermission.ManageChannel); | |||||
Permissions.SetValue(ref value, readMessages, ChannelPermission.ReadMessages); | |||||
Permissions.SetValue(ref value, sendMessages, ChannelPermission.SendMessages); | |||||
Permissions.SetValue(ref value, sendTTSMessages, ChannelPermission.SendTTSMessages); | |||||
Permissions.SetValue(ref value, manageMessages, ChannelPermission.ManageMessages); | |||||
Permissions.SetValue(ref value, embedLinks, ChannelPermission.EmbedLinks); | |||||
Permissions.SetValue(ref value, attachFiles, ChannelPermission.AttachFiles); | |||||
Permissions.SetValue(ref value, readMessageHistory, ChannelPermission.ReadMessageHistory); | |||||
Permissions.SetValue(ref value, mentionEveryone, ChannelPermission.MentionEveryone); | |||||
Permissions.SetValue(ref value, connect, ChannelPermission.Connect); | |||||
Permissions.SetValue(ref value, speak, ChannelPermission.Speak); | |||||
Permissions.SetValue(ref value, muteMembers, ChannelPermission.MuteMembers); | |||||
Permissions.SetValue(ref value, deafenMembers, ChannelPermission.DeafenMembers); | |||||
Permissions.SetValue(ref value, moveMembers, ChannelPermission.MoveMembers); | |||||
Permissions.SetValue(ref value, useVoiceActivation, ChannelPermission.UseVAD); | |||||
Permissions.SetValue(ref value, managePermissions, ChannelPermission.ManagePermissions); | |||||
RawValue = value; | |||||
} | |||||
/// <summary> Creates a new ChannelPermissions with the provided permissions. </summary> | |||||
public ChannelPermissions(bool createInstantInvite = false, bool manageChannel = false, | |||||
bool readMessages = false, bool sendMessages = false, bool sendTTSMessages = false, bool manageMessages = false, | |||||
bool embedLinks = false, bool attachFiles = false, bool readMessageHistory = false, bool mentionEveryone = false, | |||||
bool connect = false, bool speak = false, bool muteMembers = false, bool deafenMembers = false, | |||||
bool moveMembers = false, bool useVoiceActivation = false, bool managePermissions = false) | |||||
: this(0, createInstantInvite, manageChannel, readMessages, sendMessages, sendTTSMessages, manageMessages, | |||||
embedLinks, attachFiles, readMessageHistory, mentionEveryone, connect, speak, muteMembers, deafenMembers, | |||||
moveMembers, useVoiceActivation, managePermissions) { } | |||||
/// <summary> Creates a new ChannelPermissions from this one, changing the provided non-null permissions. </summary> | |||||
public ChannelPermissions Modify(bool? createInstantInvite = null, bool? manageChannel = null, | |||||
bool? readMessages = null, bool? sendMessages = null, bool? sendTTSMessages = null, bool? manageMessages = null, | |||||
bool? embedLinks = null, bool? attachFiles = null, bool? readMessageHistory = null, bool? mentionEveryone = null, | |||||
bool? connect = null, bool? speak = null, bool? muteMembers = null, bool? deafenMembers = null, | |||||
bool? moveMembers = null, bool? useVoiceActivation = null, bool? managePermissions = null) | |||||
=> new ChannelPermissions(RawValue, createInstantInvite, manageChannel, readMessages, sendMessages, sendTTSMessages, manageMessages, | |||||
embedLinks, attachFiles, readMessageHistory, mentionEveryone, connect, speak, muteMembers, deafenMembers, | |||||
moveMembers, useVoiceActivation, managePermissions); | |||||
public List<ChannelPermission> ToList() | |||||
{ | |||||
var perms = new List<ChannelPermission>(); | |||||
ulong x = 1; | |||||
for (byte i = 0; i < Permissions.MaxBits; i++, x <<= 1) | |||||
{ | |||||
if ((RawValue & x) != 0) | |||||
perms.Add((ChannelPermission)i); | |||||
} | |||||
return perms; | |||||
} | |||||
/// <inheritdoc /> | |||||
public override string ToString() => RawValue.ToString(); | |||||
private string DebuggerDisplay => $"{RawValue} ({string.Join(", ", ToList())})"; | |||||
} | |||||
} |
@@ -1,6 +1,6 @@ | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
internal enum GuildPermission : byte | |||||
public enum GuildPermission : byte | |||||
{ | { | ||||
//General | //General | ||||
CreateInstantInvite = 0, | CreateInstantInvite = 0, |
@@ -1,71 +1,78 @@ | |||||
using System.Collections.Generic; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Diagnostics; | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] | |||||
public struct GuildPermissions | public struct GuildPermissions | ||||
{ | { | ||||
/// <summary> Gets a blank GuildPermissions that grants no permissions. </summary> | /// <summary> Gets a blank GuildPermissions that grants no permissions. </summary> | ||||
public static readonly GuildPermissions None = new GuildPermissions(); | public static readonly GuildPermissions None = new GuildPermissions(); | ||||
/// <summary> Gets a GuildPermissions that grants all permissions. </summary> | /// <summary> Gets a GuildPermissions that grants all permissions. </summary> | ||||
#if CSHARP7 | |||||
public static readonly GuildPermissions All = new GuildPermissions(0b000111_111111_0011111111_0000111111); | public static readonly GuildPermissions All = new GuildPermissions(0b000111_111111_0011111111_0000111111); | ||||
#else | |||||
public static readonly GuildPermissions All = new GuildPermissions(Convert.ToUInt64("00011111111100111111110000111111", 2)); | |||||
#endif | |||||
/// <summary> Gets a packed value representing all the permissions in this GuildPermissions. </summary> | /// <summary> Gets a packed value representing all the permissions in this GuildPermissions. </summary> | ||||
public uint RawValue { get; } | |||||
public ulong RawValue { get; } | |||||
/// <summary> If True, a user may create invites. </summary> | /// <summary> If True, a user may create invites. </summary> | ||||
public bool CreateInstantInvite => PermissionUtilities.GetValue(RawValue, GuildPermission.CreateInstantInvite); | |||||
public bool CreateInstantInvite => Permissions.GetValue(RawValue, GuildPermission.CreateInstantInvite); | |||||
/// <summary> If True, a user may ban users from the guild. </summary> | /// <summary> If True, a user may ban users from the guild. </summary> | ||||
public bool BanMembers => PermissionUtilities.GetValue(RawValue, GuildPermission.BanMembers); | |||||
public bool BanMembers => Permissions.GetValue(RawValue, GuildPermission.BanMembers); | |||||
/// <summary> If True, a user may kick users from the guild. </summary> | /// <summary> If True, a user may kick users from the guild. </summary> | ||||
public bool KickMembers => PermissionUtilities.GetValue(RawValue, GuildPermission.KickMembers); | |||||
public bool KickMembers => Permissions.GetValue(RawValue, GuildPermission.KickMembers); | |||||
/// <summary> If True, a user is granted all permissions, and cannot have them revoked via channel permissions. </summary> | /// <summary> If True, a user is granted all permissions, and cannot have them revoked via channel permissions. </summary> | ||||
public bool Administrator => PermissionUtilities.GetValue(RawValue, GuildPermission.Administrator); | |||||
public bool Administrator => Permissions.GetValue(RawValue, GuildPermission.Administrator); | |||||
/// <summary> If True, a user may create, delete and modify channels. </summary> | /// <summary> If True, a user may create, delete and modify channels. </summary> | ||||
public bool ManageChannels => PermissionUtilities.GetValue(RawValue, GuildPermission.ManageChannels); | |||||
public bool ManageChannels => Permissions.GetValue(RawValue, GuildPermission.ManageChannels); | |||||
/// <summary> If True, a user may adjust guild properties. </summary> | /// <summary> If True, a user may adjust guild properties. </summary> | ||||
public bool ManageGuild => PermissionUtilities.GetValue(RawValue, GuildPermission.ManageGuild); | |||||
public bool ManageGuild => Permissions.GetValue(RawValue, GuildPermission.ManageGuild); | |||||
/// <summary> If True, a user may join channels. </summary> | /// <summary> If True, a user may join channels. </summary> | ||||
public bool ReadMessages => PermissionUtilities.GetValue(RawValue, GuildPermission.ReadMessages); | |||||
public bool ReadMessages => Permissions.GetValue(RawValue, GuildPermission.ReadMessages); | |||||
/// <summary> If True, a user may send messages. </summary> | /// <summary> If True, a user may send messages. </summary> | ||||
public bool SendMessages => PermissionUtilities.GetValue(RawValue, GuildPermission.SendMessages); | |||||
public bool SendMessages => Permissions.GetValue(RawValue, GuildPermission.SendMessages); | |||||
/// <summary> If True, a user may send text-to-speech messages. </summary> | /// <summary> If True, a user may send text-to-speech messages. </summary> | ||||
public bool SendTTSMessages => PermissionUtilities.GetValue(RawValue, GuildPermission.SendTTSMessages); | |||||
public bool SendTTSMessages => Permissions.GetValue(RawValue, GuildPermission.SendTTSMessages); | |||||
/// <summary> If True, a user may delete messages. </summary> | /// <summary> If True, a user may delete messages. </summary> | ||||
public bool ManageMessages => PermissionUtilities.GetValue(RawValue, GuildPermission.ManageMessages); | |||||
public bool ManageMessages => Permissions.GetValue(RawValue, GuildPermission.ManageMessages); | |||||
/// <summary> If True, Discord will auto-embed links sent by this user. </summary> | /// <summary> If True, Discord will auto-embed links sent by this user. </summary> | ||||
public bool EmbedLinks => PermissionUtilities.GetValue(RawValue, GuildPermission.EmbedLinks); | |||||
public bool EmbedLinks => Permissions.GetValue(RawValue, GuildPermission.EmbedLinks); | |||||
/// <summary> If True, a user may send files. </summary> | /// <summary> If True, a user may send files. </summary> | ||||
public bool AttachFiles => PermissionUtilities.GetValue(RawValue, GuildPermission.AttachFiles); | |||||
public bool AttachFiles => Permissions.GetValue(RawValue, GuildPermission.AttachFiles); | |||||
/// <summary> If True, a user may read previous messages. </summary> | /// <summary> If True, a user may read previous messages. </summary> | ||||
public bool ReadMessageHistory => PermissionUtilities.GetValue(RawValue, GuildPermission.ReadMessageHistory); | |||||
public bool ReadMessageHistory => Permissions.GetValue(RawValue, GuildPermission.ReadMessageHistory); | |||||
/// <summary> If True, a user may mention @everyone. </summary> | /// <summary> If True, a user may mention @everyone. </summary> | ||||
public bool MentionEveryone => PermissionUtilities.GetValue(RawValue, GuildPermission.MentionEveryone); | |||||
public bool MentionEveryone => Permissions.GetValue(RawValue, GuildPermission.MentionEveryone); | |||||
/// <summary> If True, a user may connect to a voice channel. </summary> | /// <summary> If True, a user may connect to a voice channel. </summary> | ||||
public bool Connect => PermissionUtilities.GetValue(RawValue, GuildPermission.Connect); | |||||
public bool Connect => Permissions.GetValue(RawValue, GuildPermission.Connect); | |||||
/// <summary> If True, a user may speak in a voice channel. </summary> | /// <summary> If True, a user may speak in a voice channel. </summary> | ||||
public bool Speak => PermissionUtilities.GetValue(RawValue, GuildPermission.Speak); | |||||
public bool Speak => Permissions.GetValue(RawValue, GuildPermission.Speak); | |||||
/// <summary> If True, a user may mute users. </summary> | /// <summary> If True, a user may mute users. </summary> | ||||
public bool MuteMembers => PermissionUtilities.GetValue(RawValue, GuildPermission.MuteMembers); | |||||
public bool MuteMembers => Permissions.GetValue(RawValue, GuildPermission.MuteMembers); | |||||
/// <summary> If True, a user may deafen users. </summary> | /// <summary> If True, a user may deafen users. </summary> | ||||
public bool DeafenMembers => PermissionUtilities.GetValue(RawValue, GuildPermission.DeafenMembers); | |||||
public bool DeafenMembers => Permissions.GetValue(RawValue, GuildPermission.DeafenMembers); | |||||
/// <summary> If True, a user may move other users between voice channels. </summary> | /// <summary> If True, a user may move other users between voice channels. </summary> | ||||
public bool MoveMembers => PermissionUtilities.GetValue(RawValue, GuildPermission.MoveMembers); | |||||
public bool MoveMembers => Permissions.GetValue(RawValue, GuildPermission.MoveMembers); | |||||
/// <summary> If True, a user may use voice-activity-detection rather than push-to-talk. </summary> | /// <summary> If True, a user may use voice-activity-detection rather than push-to-talk. </summary> | ||||
public bool UseVAD => PermissionUtilities.GetValue(RawValue, GuildPermission.UseVAD); | |||||
public bool UseVAD => Permissions.GetValue(RawValue, GuildPermission.UseVAD); | |||||
/// <summary> If True, a user may change their own nickname. </summary> | /// <summary> If True, a user may change their own nickname. </summary> | ||||
public bool ChangeNickname => PermissionUtilities.GetValue(RawValue, GuildPermission.ChangeNickname); | |||||
public bool ChangeNickname => Permissions.GetValue(RawValue, GuildPermission.ChangeNickname); | |||||
/// <summary> If True, a user may change the nickname of other users. </summary> | /// <summary> If True, a user may change the nickname of other users. </summary> | ||||
public bool ManageNicknames => PermissionUtilities.GetValue(RawValue, GuildPermission.ManageNicknames); | |||||
public bool ManageNicknames => Permissions.GetValue(RawValue, GuildPermission.ManageNicknames); | |||||
/// <summary> If True, a user may adjust roles. </summary> | /// <summary> If True, a user may adjust roles. </summary> | ||||
public bool ManageRoles => PermissionUtilities.GetValue(RawValue, GuildPermission.ManageRoles); | |||||
public bool ManageRoles => Permissions.GetValue(RawValue, GuildPermission.ManageRoles); | |||||
/// <summary> Creates a new GuildPermissions with the provided packed value. </summary> | /// <summary> Creates a new GuildPermissions with the provided packed value. </summary> | ||||
public GuildPermissions(uint rawValue) { RawValue = rawValue; } | |||||
public GuildPermissions(ulong rawValue) { RawValue = rawValue; } | |||||
private GuildPermissions(uint initialValue, bool? createInstantInvite = null, bool? kickMembers = null, | |||||
private GuildPermissions(ulong initialValue, bool? createInstantInvite = null, bool? kickMembers = null, | |||||
bool? banMembers = null, bool? administrator = null, bool? manageChannel = null, bool? manageGuild = null, | bool? banMembers = null, bool? administrator = null, bool? manageChannel = null, bool? manageGuild = null, | ||||
bool? readMessages = null, bool? sendMessages = null, bool? sendTTSMessages = null, bool? manageMessages = null, | bool? readMessages = null, bool? sendMessages = null, bool? sendTTSMessages = null, bool? manageMessages = null, | ||||
bool? embedLinks = null, bool? attachFiles = null, bool? readMessageHistory = null, bool? mentionEveryone = null, | bool? embedLinks = null, bool? attachFiles = null, bool? readMessageHistory = null, bool? mentionEveryone = null, | ||||
@@ -73,31 +80,31 @@ namespace Discord | |||||
bool? moveMembers = null, bool? useVoiceActivation = null, bool? changeNickname = null, bool? manageNicknames = null, | bool? moveMembers = null, bool? useVoiceActivation = null, bool? changeNickname = null, bool? manageNicknames = null, | ||||
bool? manageRoles = null) | bool? manageRoles = null) | ||||
{ | { | ||||
uint value = initialValue; | |||||
ulong value = initialValue; | |||||
PermissionUtilities.SetValue(ref value, createInstantInvite, GuildPermission.CreateInstantInvite); | |||||
PermissionUtilities.SetValue(ref value, banMembers, GuildPermission.BanMembers); | |||||
PermissionUtilities.SetValue(ref value, kickMembers, GuildPermission.KickMembers); | |||||
PermissionUtilities.SetValue(ref value, administrator, GuildPermission.Administrator); | |||||
PermissionUtilities.SetValue(ref value, manageChannel, GuildPermission.ManageChannels); | |||||
PermissionUtilities.SetValue(ref value, manageGuild, GuildPermission.ManageGuild); | |||||
PermissionUtilities.SetValue(ref value, readMessages, GuildPermission.ReadMessages); | |||||
PermissionUtilities.SetValue(ref value, sendMessages, GuildPermission.SendMessages); | |||||
PermissionUtilities.SetValue(ref value, sendTTSMessages, GuildPermission.SendTTSMessages); | |||||
PermissionUtilities.SetValue(ref value, manageMessages, GuildPermission.ManageMessages); | |||||
PermissionUtilities.SetValue(ref value, embedLinks, GuildPermission.EmbedLinks); | |||||
PermissionUtilities.SetValue(ref value, attachFiles, GuildPermission.AttachFiles); | |||||
PermissionUtilities.SetValue(ref value, readMessageHistory, GuildPermission.ReadMessageHistory); | |||||
PermissionUtilities.SetValue(ref value, mentionEveryone, GuildPermission.MentionEveryone); | |||||
PermissionUtilities.SetValue(ref value, connect, GuildPermission.Connect); | |||||
PermissionUtilities.SetValue(ref value, speak, GuildPermission.Speak); | |||||
PermissionUtilities.SetValue(ref value, muteMembers, GuildPermission.MuteMembers); | |||||
PermissionUtilities.SetValue(ref value, deafenMembers, GuildPermission.DeafenMembers); | |||||
PermissionUtilities.SetValue(ref value, moveMembers, GuildPermission.MoveMembers); | |||||
PermissionUtilities.SetValue(ref value, useVoiceActivation, GuildPermission.UseVAD); | |||||
PermissionUtilities.SetValue(ref value, changeNickname, GuildPermission.ChangeNickname); | |||||
PermissionUtilities.SetValue(ref value, manageNicknames, GuildPermission.ManageNicknames); | |||||
PermissionUtilities.SetValue(ref value, manageRoles, GuildPermission.ManageRoles); | |||||
Permissions.SetValue(ref value, createInstantInvite, GuildPermission.CreateInstantInvite); | |||||
Permissions.SetValue(ref value, banMembers, GuildPermission.BanMembers); | |||||
Permissions.SetValue(ref value, kickMembers, GuildPermission.KickMembers); | |||||
Permissions.SetValue(ref value, administrator, GuildPermission.Administrator); | |||||
Permissions.SetValue(ref value, manageChannel, GuildPermission.ManageChannels); | |||||
Permissions.SetValue(ref value, manageGuild, GuildPermission.ManageGuild); | |||||
Permissions.SetValue(ref value, readMessages, GuildPermission.ReadMessages); | |||||
Permissions.SetValue(ref value, sendMessages, GuildPermission.SendMessages); | |||||
Permissions.SetValue(ref value, sendTTSMessages, GuildPermission.SendTTSMessages); | |||||
Permissions.SetValue(ref value, manageMessages, GuildPermission.ManageMessages); | |||||
Permissions.SetValue(ref value, embedLinks, GuildPermission.EmbedLinks); | |||||
Permissions.SetValue(ref value, attachFiles, GuildPermission.AttachFiles); | |||||
Permissions.SetValue(ref value, readMessageHistory, GuildPermission.ReadMessageHistory); | |||||
Permissions.SetValue(ref value, mentionEveryone, GuildPermission.MentionEveryone); | |||||
Permissions.SetValue(ref value, connect, GuildPermission.Connect); | |||||
Permissions.SetValue(ref value, speak, GuildPermission.Speak); | |||||
Permissions.SetValue(ref value, muteMembers, GuildPermission.MuteMembers); | |||||
Permissions.SetValue(ref value, deafenMembers, GuildPermission.DeafenMembers); | |||||
Permissions.SetValue(ref value, moveMembers, GuildPermission.MoveMembers); | |||||
Permissions.SetValue(ref value, useVoiceActivation, GuildPermission.UseVAD); | |||||
Permissions.SetValue(ref value, changeNickname, GuildPermission.ChangeNickname); | |||||
Permissions.SetValue(ref value, manageNicknames, GuildPermission.ManageNicknames); | |||||
Permissions.SetValue(ref value, manageRoles, GuildPermission.ManageRoles); | |||||
RawValue = value; | RawValue = value; | ||||
} | } | ||||
@@ -125,21 +132,20 @@ namespace Discord | |||||
=> new GuildPermissions(RawValue, createInstantInvite, manageRoles, kickMembers, banMembers, manageChannels, manageGuild, readMessages, | => new GuildPermissions(RawValue, createInstantInvite, manageRoles, kickMembers, banMembers, manageChannels, manageGuild, readMessages, | ||||
sendMessages, sendTTSMessages, manageMessages, embedLinks, attachFiles, mentionEveryone, connect, speak, muteMembers, deafenMembers, | sendMessages, sendTTSMessages, manageMessages, embedLinks, attachFiles, mentionEveryone, connect, speak, muteMembers, deafenMembers, | ||||
moveMembers, useVoiceActivation, changeNickname, manageNicknames, manageRoles); | moveMembers, useVoiceActivation, changeNickname, manageNicknames, manageRoles); | ||||
/// <inheritdoc /> | |||||
public override string ToString() | |||||
public List<GuildPermission> ToList() | |||||
{ | { | ||||
var perms = new List<string>(); | |||||
int x = 1; | |||||
for (byte i = 0; i < 32; i++, x <<= 1) | |||||
var perms = new List<GuildPermission>(); | |||||
ulong x = 1; | |||||
for (byte i = 0; i < Permissions.MaxBits; i++, x <<= 1) | |||||
{ | { | ||||
if ((RawValue & x) != 0) | if ((RawValue & x) != 0) | ||||
{ | |||||
if (System.Enum.IsDefined(typeof(GuildPermission), i)) | |||||
perms.Add($"{(GuildPermission)i}"); | |||||
} | |||||
perms.Add((GuildPermission)i); | |||||
} | } | ||||
return string.Join(", ", perms); | |||||
return perms; | |||||
} | } | ||||
/// <inheritdoc /> | |||||
public override string ToString() => RawValue.ToString(); | |||||
private string DebuggerDisplay => $"{RawValue} ({string.Join(", ", ToList())})"; | |||||
} | } | ||||
} | } |
@@ -1,8 +1,10 @@ | |||||
using System; | using System; | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.Diagnostics; | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] | |||||
public struct OverwritePermissions | public struct OverwritePermissions | ||||
{ | { | ||||
/// <summary> Gets a blank OverwritePermissions that inherits all permissions. </summary> | /// <summary> Gets a blank OverwritePermissions that inherits all permissions. </summary> | ||||
@@ -15,77 +17,77 @@ namespace Discord | |||||
=> new OverwritePermissions(0, ChannelPermissions.All(channel).RawValue); | => new OverwritePermissions(0, ChannelPermissions.All(channel).RawValue); | ||||
/// <summary> Gets a packed value representing all the allowed permissions in this OverwritePermissions. </summary> | /// <summary> Gets a packed value representing all the allowed permissions in this OverwritePermissions. </summary> | ||||
public uint AllowValue { get; } | |||||
public ulong AllowValue { get; } | |||||
/// <summary> Gets a packed value representing all the denied permissions in this OverwritePermissions. </summary> | /// <summary> Gets a packed value representing all the denied permissions in this OverwritePermissions. </summary> | ||||
public uint DenyValue { get; } | |||||
public ulong DenyValue { get; } | |||||
/// <summary> If True, a user may create invites. </summary> | /// <summary> If True, a user may create invites. </summary> | ||||
public PermValue CreateInstantInvite => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.CreateInstantInvite); | |||||
public PermValue CreateInstantInvite => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.CreateInstantInvite); | |||||
/// <summary> If True, a user may create, delete and modify this channel. </summary> | /// <summary> If True, a user may create, delete and modify this channel. </summary> | ||||
public PermValue ManageChannel => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.ManageChannel); | |||||
public PermValue ManageChannel => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.ManageChannel); | |||||
/// <summary> If True, a user may join channels. </summary> | /// <summary> If True, a user may join channels. </summary> | ||||
public PermValue ReadMessages => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.ReadMessages); | |||||
public PermValue ReadMessages => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.ReadMessages); | |||||
/// <summary> If True, a user may send messages. </summary> | /// <summary> If True, a user may send messages. </summary> | ||||
public PermValue SendMessages => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.SendMessages); | |||||
public PermValue SendMessages => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.SendMessages); | |||||
/// <summary> If True, a user may send text-to-speech messages. </summary> | /// <summary> If True, a user may send text-to-speech messages. </summary> | ||||
public PermValue SendTTSMessages => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.SendTTSMessages); | |||||
public PermValue SendTTSMessages => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.SendTTSMessages); | |||||
/// <summary> If True, a user may delete messages. </summary> | /// <summary> If True, a user may delete messages. </summary> | ||||
public PermValue ManageMessages => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.ManageMessages); | |||||
public PermValue ManageMessages => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.ManageMessages); | |||||
/// <summary> If True, Discord will auto-embed links sent by this user. </summary> | /// <summary> If True, Discord will auto-embed links sent by this user. </summary> | ||||
public PermValue EmbedLinks => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.EmbedLinks); | |||||
public PermValue EmbedLinks => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.EmbedLinks); | |||||
/// <summary> If True, a user may send files. </summary> | /// <summary> If True, a user may send files. </summary> | ||||
public PermValue AttachFiles => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.AttachFiles); | |||||
public PermValue AttachFiles => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.AttachFiles); | |||||
/// <summary> If True, a user may read previous messages. </summary> | /// <summary> If True, a user may read previous messages. </summary> | ||||
public PermValue ReadMessageHistory => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.ReadMessageHistory); | |||||
public PermValue ReadMessageHistory => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.ReadMessageHistory); | |||||
/// <summary> If True, a user may mention @everyone. </summary> | /// <summary> If True, a user may mention @everyone. </summary> | ||||
public PermValue MentionEveryone => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.MentionEveryone); | |||||
public PermValue MentionEveryone => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.MentionEveryone); | |||||
/// <summary> If True, a user may connect to a voice channel. </summary> | /// <summary> If True, a user may connect to a voice channel. </summary> | ||||
public PermValue Connect => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.Connect); | |||||
public PermValue Connect => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.Connect); | |||||
/// <summary> If True, a user may speak in a voice channel. </summary> | /// <summary> If True, a user may speak in a voice channel. </summary> | ||||
public PermValue Speak => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.Speak); | |||||
public PermValue Speak => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.Speak); | |||||
/// <summary> If True, a user may mute users. </summary> | /// <summary> If True, a user may mute users. </summary> | ||||
public PermValue MuteMembers => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.MuteMembers); | |||||
public PermValue MuteMembers => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.MuteMembers); | |||||
/// <summary> If True, a user may deafen users. </summary> | /// <summary> If True, a user may deafen users. </summary> | ||||
public PermValue DeafenMembers => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.DeafenMembers); | |||||
public PermValue DeafenMembers => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.DeafenMembers); | |||||
/// <summary> If True, a user may move other users between voice channels. </summary> | /// <summary> If True, a user may move other users between voice channels. </summary> | ||||
public PermValue MoveMembers => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.MoveMembers); | |||||
public PermValue MoveMembers => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.MoveMembers); | |||||
/// <summary> If True, a user may use voice-activity-detection rather than push-to-talk. </summary> | /// <summary> If True, a user may use voice-activity-detection rather than push-to-talk. </summary> | ||||
public PermValue UseVAD => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.UseVAD); | |||||
public PermValue UseVAD => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.UseVAD); | |||||
/// <summary> If True, a user may adjust permissions. This also implictly grants all other permissions. </summary> | /// <summary> If True, a user may adjust permissions. This also implictly grants all other permissions. </summary> | ||||
public PermValue ManagePermissions => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.ManagePermissions); | |||||
public PermValue ManagePermissions => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.ManagePermissions); | |||||
/// <summary> Creates a new OverwritePermissions with the provided allow and deny packed values. </summary> | /// <summary> Creates a new OverwritePermissions with the provided allow and deny packed values. </summary> | ||||
public OverwritePermissions(uint allowValue, uint denyValue) | |||||
public OverwritePermissions(ulong allowValue, ulong denyValue) | |||||
{ | { | ||||
AllowValue = allowValue; | AllowValue = allowValue; | ||||
DenyValue = denyValue; | DenyValue = denyValue; | ||||
} | } | ||||
private OverwritePermissions(uint allowValue, uint denyValue, PermValue? createInstantInvite = null, PermValue? manageChannel = null, | |||||
private OverwritePermissions(ulong allowValue, ulong denyValue, PermValue? createInstantInvite = null, PermValue? manageChannel = null, | |||||
PermValue? readMessages = null, PermValue? sendMessages = null, PermValue? sendTTSMessages = null, PermValue? manageMessages = null, | PermValue? readMessages = null, PermValue? sendMessages = null, PermValue? sendTTSMessages = null, PermValue? manageMessages = null, | ||||
PermValue? embedLinks = null, PermValue? attachFiles = null, PermValue? readMessageHistory = null, PermValue? mentionEveryone = null, | PermValue? embedLinks = null, PermValue? attachFiles = null, PermValue? readMessageHistory = null, PermValue? mentionEveryone = null, | ||||
PermValue? connect = null, PermValue? speak = null, PermValue? muteMembers = null, PermValue? deafenMembers = null, | PermValue? connect = null, PermValue? speak = null, PermValue? muteMembers = null, PermValue? deafenMembers = null, | ||||
PermValue? moveMembers = null, PermValue? useVoiceActivation = null, PermValue? managePermissions = null) | PermValue? moveMembers = null, PermValue? useVoiceActivation = null, PermValue? managePermissions = null) | ||||
{ | { | ||||
PermissionUtilities.SetValue(ref allowValue, ref denyValue, createInstantInvite, ChannelPermission.CreateInstantInvite); | |||||
PermissionUtilities.SetValue(ref allowValue, ref denyValue, manageChannel, ChannelPermission.ManageChannel); | |||||
PermissionUtilities.SetValue(ref allowValue, ref denyValue, readMessages, ChannelPermission.ReadMessages); | |||||
PermissionUtilities.SetValue(ref allowValue, ref denyValue, sendMessages, ChannelPermission.SendMessages); | |||||
PermissionUtilities.SetValue(ref allowValue, ref denyValue, sendTTSMessages, ChannelPermission.SendTTSMessages); | |||||
PermissionUtilities.SetValue(ref allowValue, ref denyValue, manageMessages, ChannelPermission.ManageMessages); | |||||
PermissionUtilities.SetValue(ref allowValue, ref denyValue, embedLinks, ChannelPermission.EmbedLinks); | |||||
PermissionUtilities.SetValue(ref allowValue, ref denyValue, attachFiles, ChannelPermission.AttachFiles); | |||||
PermissionUtilities.SetValue(ref allowValue, ref denyValue, readMessageHistory, ChannelPermission.ReadMessageHistory); | |||||
PermissionUtilities.SetValue(ref allowValue, ref denyValue, mentionEveryone, ChannelPermission.MentionEveryone); | |||||
PermissionUtilities.SetValue(ref allowValue, ref denyValue, connect, ChannelPermission.Connect); | |||||
PermissionUtilities.SetValue(ref allowValue, ref denyValue, speak, ChannelPermission.Speak); | |||||
PermissionUtilities.SetValue(ref allowValue, ref denyValue, muteMembers, ChannelPermission.MuteMembers); | |||||
PermissionUtilities.SetValue(ref allowValue, ref denyValue, deafenMembers, ChannelPermission.DeafenMembers); | |||||
PermissionUtilities.SetValue(ref allowValue, ref denyValue, moveMembers, ChannelPermission.MoveMembers); | |||||
PermissionUtilities.SetValue(ref allowValue, ref denyValue, useVoiceActivation, ChannelPermission.UseVAD); | |||||
PermissionUtilities.SetValue(ref allowValue, ref denyValue, managePermissions, ChannelPermission.ManagePermissions); | |||||
Permissions.SetValue(ref allowValue, ref denyValue, createInstantInvite, ChannelPermission.CreateInstantInvite); | |||||
Permissions.SetValue(ref allowValue, ref denyValue, manageChannel, ChannelPermission.ManageChannel); | |||||
Permissions.SetValue(ref allowValue, ref denyValue, readMessages, ChannelPermission.ReadMessages); | |||||
Permissions.SetValue(ref allowValue, ref denyValue, sendMessages, ChannelPermission.SendMessages); | |||||
Permissions.SetValue(ref allowValue, ref denyValue, sendTTSMessages, ChannelPermission.SendTTSMessages); | |||||
Permissions.SetValue(ref allowValue, ref denyValue, manageMessages, ChannelPermission.ManageMessages); | |||||
Permissions.SetValue(ref allowValue, ref denyValue, embedLinks, ChannelPermission.EmbedLinks); | |||||
Permissions.SetValue(ref allowValue, ref denyValue, attachFiles, ChannelPermission.AttachFiles); | |||||
Permissions.SetValue(ref allowValue, ref denyValue, readMessageHistory, ChannelPermission.ReadMessageHistory); | |||||
Permissions.SetValue(ref allowValue, ref denyValue, mentionEveryone, ChannelPermission.MentionEveryone); | |||||
Permissions.SetValue(ref allowValue, ref denyValue, connect, ChannelPermission.Connect); | |||||
Permissions.SetValue(ref allowValue, ref denyValue, speak, ChannelPermission.Speak); | |||||
Permissions.SetValue(ref allowValue, ref denyValue, muteMembers, ChannelPermission.MuteMembers); | |||||
Permissions.SetValue(ref allowValue, ref denyValue, deafenMembers, ChannelPermission.DeafenMembers); | |||||
Permissions.SetValue(ref allowValue, ref denyValue, moveMembers, ChannelPermission.MoveMembers); | |||||
Permissions.SetValue(ref allowValue, ref denyValue, useVoiceActivation, ChannelPermission.UseVAD); | |||||
Permissions.SetValue(ref allowValue, ref denyValue, managePermissions, ChannelPermission.ManagePermissions); | |||||
AllowValue = allowValue; | AllowValue = allowValue; | ||||
DenyValue = denyValue; | DenyValue = denyValue; | ||||
@@ -111,25 +113,32 @@ namespace Discord | |||||
embedLinks, attachFiles, readMessageHistory, mentionEveryone, connect, speak, muteMembers, deafenMembers, | embedLinks, attachFiles, readMessageHistory, mentionEveryone, connect, speak, muteMembers, deafenMembers, | ||||
moveMembers, useVoiceActivation, managePermissions); | moveMembers, useVoiceActivation, managePermissions); | ||||
/// <inheritdoc /> | |||||
public override string ToString() | |||||
public List<ChannelPermission> ToAllowList() | |||||
{ | { | ||||
var perms = new List<string>(); | |||||
int x = 1; | |||||
for (byte i = 0; i < 32; i++, x <<= 1) | |||||
var perms = new List<ChannelPermission>(); | |||||
ulong x = 1; | |||||
for (byte i = 0; i < Permissions.MaxBits; i++, x <<= 1) | |||||
{ | { | ||||
if ((AllowValue & x) != 0) | if ((AllowValue & x) != 0) | ||||
{ | |||||
if (Enum.IsDefined(typeof(GuildPermission), i)) | |||||
perms.Add($"+{(GuildPermission)i}"); | |||||
} | |||||
else if ((DenyValue & x) != 0) | |||||
{ | |||||
if (Enum.IsDefined(typeof(GuildPermission), i)) | |||||
perms.Add($"-{(GuildPermission)i}"); | |||||
} | |||||
perms.Add((ChannelPermission)i); | |||||
} | |||||
return perms; | |||||
} | |||||
public List<ChannelPermission> ToDenyList() | |||||
{ | |||||
var perms = new List<ChannelPermission>(); | |||||
ulong x = 1; | |||||
for (byte i = 0; i < Permissions.MaxBits; i++, x <<= 1) | |||||
{ | |||||
if ((DenyValue & x) != 0) | |||||
perms.Add((ChannelPermission)i); | |||||
} | } | ||||
return string.Join(", ", perms); | |||||
return perms; | |||||
} | } | ||||
/// <inheritdoc /> | |||||
public override string ToString() => $"Allow {AllowValue}, Deny {DenyValue}"; | |||||
private string DebuggerDisplay => | |||||
$"Allow {AllowValue} ({string.Join(", ", ToAllowList())})\n" + | |||||
$"Deny {DenyValue} ({string.Join(", ", ToDenyList())})"; | |||||
} | } | ||||
} | } |
@@ -0,0 +1,159 @@ | |||||
using System.Runtime.CompilerServices; | |||||
namespace Discord | |||||
{ | |||||
internal static class Permissions | |||||
{ | |||||
public const int MaxBits = 53; | |||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||||
public static PermValue GetValue(ulong allow, ulong deny, ChannelPermission bit) | |||||
=> GetValue(allow, deny, (byte)bit); | |||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||||
public static PermValue GetValue(ulong allow, ulong deny, GuildPermission bit) | |||||
=> GetValue(allow, deny, (byte)bit); | |||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||||
public static PermValue GetValue(ulong allow, ulong deny, byte bit) | |||||
{ | |||||
if (HasBit(allow, bit)) | |||||
return PermValue.Allow; | |||||
else if (HasBit(deny, bit)) | |||||
return PermValue.Deny; | |||||
else | |||||
return PermValue.Inherit; | |||||
} | |||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||||
public static bool GetValue(ulong value, ChannelPermission bit) | |||||
=> GetValue(value, (byte)bit); | |||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||||
public static bool GetValue(ulong value, GuildPermission bit) | |||||
=> GetValue(value, (byte)bit); | |||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||||
public static bool GetValue(ulong value, byte bit) => HasBit(value, bit); | |||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||||
public static void SetValue(ref ulong rawValue, bool? value, ChannelPermission bit) | |||||
=> SetValue(ref rawValue, value, (byte)bit); | |||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||||
public static void SetValue(ref ulong rawValue, bool? value, GuildPermission bit) | |||||
=> SetValue(ref rawValue, value, (byte)bit); | |||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||||
public static void SetValue(ref ulong rawValue, bool? value, byte bit) | |||||
{ | |||||
if (value.HasValue) | |||||
{ | |||||
if (value == true) | |||||
SetBit(ref rawValue, bit); | |||||
else | |||||
UnsetBit(ref rawValue, bit); | |||||
} | |||||
} | |||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||||
public static void SetValue(ref ulong allow, ref ulong deny, PermValue? value, ChannelPermission bit) | |||||
=> SetValue(ref allow, ref deny, value, (byte)bit); | |||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||||
public static void SetValue(ref ulong allow, ref ulong deny, PermValue? value, GuildPermission bit) | |||||
=> SetValue(ref allow, ref deny, value, (byte)bit); | |||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||||
public static void SetValue(ref ulong allow, ref ulong deny, PermValue? value, byte bit) | |||||
{ | |||||
if (value.HasValue) | |||||
{ | |||||
switch (value) | |||||
{ | |||||
case PermValue.Allow: | |||||
SetBit(ref allow, bit); | |||||
UnsetBit(ref deny, bit); | |||||
break; | |||||
case PermValue.Deny: | |||||
UnsetBit(ref allow, bit); | |||||
SetBit(ref deny, bit); | |||||
break; | |||||
default: | |||||
UnsetBit(ref allow, bit); | |||||
UnsetBit(ref deny, bit); | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||||
private static bool HasBit(ulong value, byte bit) => (value & (1U << bit)) != 0; | |||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||||
public static void SetBit(ref ulong value, byte bit) => value |= (1U << bit); | |||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||||
public static void UnsetBit(ref ulong value, byte bit) => value &= ~(1U << bit); | |||||
public static ulong ResolveGuild(IGuildUser user) | |||||
{ | |||||
var roles = user.Roles; | |||||
ulong newPermissions = 0; | |||||
for (int i = 0; i < roles.Count; i++) | |||||
newPermissions |= roles[i].Permissions.RawValue; | |||||
return newPermissions; | |||||
} | |||||
/*public static ulong ResolveChannel(IGuildUser user, IGuildChannel channel) | |||||
{ | |||||
return ResolveChannel(user, channel, ResolveGuild(user)); | |||||
}*/ | |||||
public static ulong ResolveChannel(IGuildUser user, IGuildChannel channel, ulong guildPermissions) | |||||
{ | |||||
ulong resolvedPermissions = 0; | |||||
ulong mask = ChannelPermissions.All(channel).RawValue; | |||||
if (user.Id == user.Guild.OwnerId || GetValue(resolvedPermissions, GuildPermission.Administrator)) | |||||
resolvedPermissions = mask; //Owners and administrators always have all permissions | |||||
else | |||||
{ | |||||
//Start with this user's guild permissions | |||||
resolvedPermissions = guildPermissions; | |||||
var overwrites = channel.PermissionOverwrites; | |||||
Overwrite entry; | |||||
var roles = user.Roles; | |||||
if (roles.Count > 0) | |||||
{ | |||||
for (int i = 0; i < roles.Count; i++) | |||||
{ | |||||
if (overwrites.TryGetValue(roles[i].Id, out entry)) | |||||
resolvedPermissions &= ~entry.Permissions.DenyValue; | |||||
} | |||||
for (int i = 0; i < roles.Count; i++) | |||||
{ | |||||
if (overwrites.TryGetValue(roles[i].Id, out entry)) | |||||
resolvedPermissions |= entry.Permissions.AllowValue; | |||||
} | |||||
} | |||||
if (overwrites.TryGetValue(user.Id, out entry)) | |||||
resolvedPermissions = (resolvedPermissions & ~entry.Permissions.DenyValue) | entry.Permissions.AllowValue; | |||||
#if CSHARP7 | |||||
switch (channel) | |||||
{ | |||||
case ITextChannel _: | |||||
if (!GetValue(resolvedPermissions, ChannelPermission.ReadMessages)) | |||||
resolvedPermissions = 0; //No read permission on a text channel removes all other permissions | |||||
break; | |||||
case IVoiceChannel _: | |||||
if (!GetValue(resolvedPermissions, ChannelPermission.Connect)) | |||||
resolvedPermissions = 0; //No read permission on a text channel removes all other permissions | |||||
break; | |||||
} | |||||
#else | |||||
var textChannel = channel as ITextChannel; | |||||
var voiceChannel = channel as IVoiceChannel; | |||||
if (textChannel != null && !GetValue(resolvedPermissions, ChannelPermission.ReadMessages)) | |||||
resolvedPermissions = 0; //No read permission on a text channel removes all other permissions | |||||
else if (voiceChannel != null && !GetValue(resolvedPermissions, ChannelPermission.Connect)) | |||||
resolvedPermissions = 0; //No connect permission on a voice channel removes all other permissions | |||||
#endif | |||||
resolvedPermissions &= mask; //Ensure we didnt get any permissions this channel doesnt support (from guildPerms, for example) | |||||
} | |||||
return resolvedPermissions; | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,31 @@ | |||||
using System.Collections.Generic; | |||||
using System.Diagnostics; | |||||
using Model = Discord.API.Connection; | |||||
namespace Discord | |||||
{ | |||||
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] | |||||
public class Connection : IConnection | |||||
{ | |||||
public string Id { get; } | |||||
public string Type { get; } | |||||
public string Name { get; } | |||||
public bool IsRevoked { get; } | |||||
public IEnumerable<ulong> IntegrationIds { get; } | |||||
public Connection(Model model) | |||||
{ | |||||
Id = model.Id; | |||||
Type = model.Type; | |||||
Name = model.Name; | |||||
IsRevoked = model.Revoked; | |||||
IntegrationIds = model.Integrations; | |||||
} | |||||
public override string ToString() => Name; | |||||
private string DebuggerDisplay => $"{Name} ({Id}, Type = {Type}{(IsRevoked ? ", Revoked" : "")})"; | |||||
} | |||||
} |
@@ -0,0 +1,22 @@ | |||||
namespace Discord | |||||
{ | |||||
public struct Game | |||||
{ | |||||
public string Name { get; } | |||||
public string StreamUrl { get; } | |||||
public StreamType StreamType { get; } | |||||
public Game(string name) | |||||
{ | |||||
Name = name; | |||||
StreamUrl = null; | |||||
StreamType = StreamType.NotStreaming; | |||||
} | |||||
public Game(string name, string streamUrl, StreamType type) | |||||
{ | |||||
Name = name; | |||||
StreamUrl = streamUrl; | |||||
StreamType = type; | |||||
} | |||||
} | |||||
} |
@@ -9,6 +9,6 @@ namespace Discord | |||||
string Name { get; } | string Name { get; } | ||||
bool IsRevoked { get; } | bool IsRevoked { get; } | ||||
IEnumerable<ulong> Integrations { get; } | |||||
IEnumerable<ulong> IntegrationIds { get; } | |||||
} | } | ||||
} | } |
@@ -21,17 +21,14 @@ namespace Discord | |||||
IGuild Guild { get; } | IGuild Guild { get; } | ||||
/// <summary> Returns a collection of the roles this user is a member of in this guild, including the guild's @everyone role. </summary> | /// <summary> Returns a collection of the roles this user is a member of in this guild, including the guild's @everyone role. </summary> | ||||
IReadOnlyList<IRole> Roles { get; } | IReadOnlyList<IRole> Roles { get; } | ||||
/// <summary> Gets the id of the voice channel this user is currently in, if any. </summary> | |||||
ulong? VoiceChannelId { get; } | |||||
/// <summary> Gets the voice channel this user is currently in, if any. </summary> | |||||
IVoiceChannel VoiceChannel { get; } | |||||
/// <summary> Gets the guild-level permissions granted to this user by their roles. </summary> | /// <summary> Gets the guild-level permissions granted to this user by their roles. </summary> | ||||
GuildPermissions GetGuildPermissions(); | GuildPermissions GetGuildPermissions(); | ||||
/// <summary> Gets the channel-level permissions granted to this user for a given channel. </summary> | /// <summary> Gets the channel-level permissions granted to this user for a given channel. </summary> | ||||
ChannelPermissions GetPermissions(IGuildChannel channel); | ChannelPermissions GetPermissions(IGuildChannel channel); | ||||
/// <summary> Return true if this user has the provided role. </summary> | |||||
bool HasRole(IRole role); | |||||
/// <summary> Kicks this user from this guild. </summary> | /// <summary> Kicks this user from this guild. </summary> | ||||
Task Kick(); | Task Kick(); | ||||
/// <summary> Modifies this user's properties in this guild. </summary> | /// <summary> Modifies this user's properties in this guild. </summary> |
@@ -7,7 +7,7 @@ namespace Discord | |||||
/// <summary> Gets the url to this user's avatar. </summary> | /// <summary> Gets the url to this user's avatar. </summary> | ||||
string AvatarUrl { get; } | string AvatarUrl { get; } | ||||
/// <summary> Gets the game this user is currently playing, if any. </summary> | /// <summary> Gets the game this user is currently playing, if any. </summary> | ||||
string CurrentGame { get; } | |||||
Game? CurrentGame { get; } | |||||
/// <summary> Gets the per-username unique id for this user. </summary> | /// <summary> Gets the per-username unique id for this user. </summary> | ||||
ushort Discriminator { get; } | ushort Discriminator { get; } | ||||
/// <summary> Returns true if this user is a bot account. </summary> | /// <summary> Returns true if this user is a bot account. </summary> | ||||
@@ -17,6 +17,7 @@ namespace Discord | |||||
/// <summary> Gets the username for this user. </summary> | /// <summary> Gets the username for this user. </summary> | ||||
string Username { get; } | string Username { get; } | ||||
//TODO: CreateDMChannel is a candidate to move to IGuildUser, and User made a common class, depending on next friends list update | |||||
/// <summary> Returns a private message channel to this user, creating one if it does not already exist. </summary> | /// <summary> Returns a private message channel to this user, creating one if it does not already exist. </summary> | ||||
Task<IDMChannel> CreateDMChannel(); | Task<IDMChannel> CreateDMChannel(); | ||||
} | } |
@@ -0,0 +1,8 @@ | |||||
namespace Discord | |||||
{ | |||||
public enum StreamType | |||||
{ | |||||
NotStreaming = 0, | |||||
Twitch = 1 | |||||
} | |||||
} |
@@ -0,0 +1,46 @@ | |||||
using System; | |||||
using System.Threading.Tasks; | |||||
namespace Discord | |||||
{ | |||||
internal static class EventExtensions | |||||
{ | |||||
//TODO: Optimize these for if there is only 1 subscriber (can we do this?) | |||||
public static async Task Raise(this Func<Task> eventHandler) | |||||
{ | |||||
var subscriptions = eventHandler?.GetInvocationList(); | |||||
if (subscriptions != null) | |||||
{ | |||||
for (int i = 0; i < subscriptions.Length; i++) | |||||
await (subscriptions[i] as Func<Task>).Invoke().ConfigureAwait(false); | |||||
} | |||||
} | |||||
public static async Task Raise<T>(this Func<T, Task> eventHandler, T arg) | |||||
{ | |||||
var subscriptions = eventHandler?.GetInvocationList(); | |||||
if (subscriptions != null) | |||||
{ | |||||
for (int i = 0; i < subscriptions.Length; i++) | |||||
await (subscriptions[i] as Func<T, Task>).Invoke(arg).ConfigureAwait(false); | |||||
} | |||||
} | |||||
public static async Task Raise<T1, T2>(this Func<T1, T2, Task> eventHandler, T1 arg1, T2 arg2) | |||||
{ | |||||
var subscriptions = eventHandler?.GetInvocationList(); | |||||
if (subscriptions != null) | |||||
{ | |||||
for (int i = 0; i < subscriptions.Length; i++) | |||||
await (subscriptions[i] as Func<T1, T2, Task>).Invoke(arg1, arg2).ConfigureAwait(false); | |||||
} | |||||
} | |||||
public static async Task Raise<T1, T2, T3>(this Func<T1, T2, T3, Task> eventHandler, T1 arg1, T2 arg2, T3 arg3) | |||||
{ | |||||
var subscriptions = eventHandler?.GetInvocationList(); | |||||
if (subscriptions != null) | |||||
{ | |||||
for (int i = 0; i < subscriptions.Length; i++) | |||||
await (subscriptions[i] as Func<T1, T2, T3, Task>).Invoke(arg1, arg2, arg3).ConfigureAwait(false); | |||||
} | |||||
} | |||||
} | |||||
} |