Browse Source

Merge remote-tracking branch 'refs/remotes/upstream/dev'

pull/62/head
Christopher F 9 years ago
parent
commit
9b23aff035
100 changed files with 2003 additions and 966 deletions
  1. +11
    -9
      README.md
  2. +6
    -0
      global.json
  3. +7
    -1
      src/Discord.Net/API/Common/Channel.cs
  4. +14
    -0
      src/Discord.Net/API/Common/Game.cs
  5. +4
    -4
      src/Discord.Net/API/Common/Overwrite.cs
  6. +1
    -1
      src/Discord.Net/API/Common/ReadState.cs
  7. +2
    -2
      src/Discord.Net/API/Common/Role.cs
  8. +2
    -2
      src/Discord.Net/API/Common/UserGuild.cs
  9. +472
    -216
      src/Discord.Net/API/DiscordAPIClient.cs
  10. +24
    -0
      src/Discord.Net/API/Gateway/GatewayOpCodes.cs
  11. +12
    -0
      src/Discord.Net/API/Gateway/GuildMembersChunkEvent.cs
  12. +12
    -0
      src/Discord.Net/API/Gateway/GuildRoleCreateEvent.cs
  13. +12
    -0
      src/Discord.Net/API/Gateway/GuildRoleUpdateEvent.cs
  14. +17
    -0
      src/Discord.Net/API/Gateway/IdentifyParams.cs
  15. +40
    -0
      src/Discord.Net/API/Gateway/ReadyEvent.cs
  16. +14
    -0
      src/Discord.Net/API/Gateway/RequestMembersParams.cs
  17. +12
    -0
      src/Discord.Net/API/Gateway/ResumeParams.cs
  18. +10
    -0
      src/Discord.Net/API/Gateway/ResumedEvent.cs
  19. +14
    -0
      src/Discord.Net/API/Gateway/TypingStartEvent.cs
  20. +12
    -0
      src/Discord.Net/API/Gateway/UpdateStatusParams.cs
  21. +16
    -0
      src/Discord.Net/API/Gateway/UpdateVoiceParams.cs
  22. +14
    -0
      src/Discord.Net/API/Gateway/VoiceServerUpdateEvent.cs
  23. +7
    -0
      src/Discord.Net/API/ImageAttribute.cs
  24. +7
    -0
      src/Discord.Net/API/Int53Attribute.cs
  25. +10
    -7
      src/Discord.Net/API/Optional.cs
  26. +2
    -3
      src/Discord.Net/API/Rest/CreateGuildParams.cs
  27. +2
    -2
      src/Discord.Net/API/Rest/ModifyChannelPermissionsParams.cs
  28. +1
    -1
      src/Discord.Net/API/Rest/ModifyCurrentUserParams.cs
  29. +1
    -1
      src/Discord.Net/API/Rest/ModifyGuildChannelsParams.cs
  30. +2
    -2
      src/Discord.Net/API/Rest/ModifyGuildParams.cs
  31. +1
    -1
      src/Discord.Net/API/Rest/ModifyGuildRoleParams.cs
  32. +1
    -1
      src/Discord.Net/API/Rest/ModifyGuildRolesParams.cs
  33. +2
    -0
      src/Discord.Net/API/Rest/ModifyVoiceChannelParams.cs
  34. +18
    -0
      src/Discord.Net/API/Voice/VoiceOpCodes.cs
  35. +16
    -0
      src/Discord.Net/API/WebSocketMessage.cs
  36. +0
    -7
      src/Discord.Net/Common/Entities/Guilds/IIntegrationAccount.cs
  37. +0
    -10
      src/Discord.Net/Common/Entities/Invites/IPublicInvite.cs
  38. +0
    -136
      src/Discord.Net/Common/Entities/Permissions/ChannelPermissions.cs
  39. +0
    -87
      src/Discord.Net/Common/Entities/Permissions/PermissionUtilities.cs
  40. +0
    -8
      src/Discord.Net/Common/Entities/Users/IDMUser.cs
  41. +0
    -20
      src/Discord.Net/Common/Events/SentRequestEventArgs.cs
  42. +0
    -13
      src/Discord.Net/Common/Helpers/EventExtensions.cs
  43. +0
    -64
      src/Discord.Net/Common/Helpers/PermissionHelper.cs
  44. +475
    -0
      src/Discord.Net/ConcurrentHashSet.cs
  45. +10
    -0
      src/Discord.Net/ConnectionState.cs
  46. +3
    -2
      src/Discord.Net/DateTimeUtils.cs
  47. +0
    -223
      src/Discord.Net/Discord.Net.csproj
  48. +19
    -0
      src/Discord.Net/Discord.Net.xproj
  49. +5
    -2
      src/Discord.Net/DiscordConfig.cs
  50. +0
    -0
      src/Discord.Net/Entities/Channels/ChannelType.cs
  51. +2
    -0
      src/Discord.Net/Entities/Channels/IChannel.cs
  52. +1
    -1
      src/Discord.Net/Entities/Channels/IDMChannel.cs
  53. +2
    -2
      src/Discord.Net/Entities/Channels/IGuildChannel.cs
  54. +6
    -2
      src/Discord.Net/Entities/Channels/IMessageChannel.cs
  55. +0
    -0
      src/Discord.Net/Entities/Channels/ITextChannel.cs
  56. +2
    -0
      src/Discord.Net/Entities/Channels/IVoiceChannel.cs
  57. +0
    -0
      src/Discord.Net/Entities/Guilds/Emoji.cs
  58. +2
    -2
      src/Discord.Net/Entities/Guilds/IGuild.cs
  59. +0
    -0
      src/Discord.Net/Entities/Guilds/IGuildEmbed.cs
  60. +1
    -1
      src/Discord.Net/Entities/Guilds/IGuildIntegration.cs
  61. +0
    -0
      src/Discord.Net/Entities/Guilds/IUserGuild.cs
  62. +0
    -0
      src/Discord.Net/Entities/Guilds/IVoiceRegion.cs
  63. +17
    -0
      src/Discord.Net/Entities/Guilds/IntegrationAccount.cs
  64. +6
    -3
      src/Discord.Net/Entities/Guilds/VoiceRegion.cs
  65. +0
    -0
      src/Discord.Net/Entities/IDeletable.cs
  66. +0
    -0
      src/Discord.Net/Entities/IEntity.cs
  67. +0
    -0
      src/Discord.Net/Entities/IMentionable.cs
  68. +0
    -0
      src/Discord.Net/Entities/ISnowflakeEntity.cs
  69. +0
    -0
      src/Discord.Net/Entities/IUpdateable.cs
  70. +1
    -1
      src/Discord.Net/Entities/Invites/IInvite.cs
  71. +1
    -4
      src/Discord.Net/Entities/Invites/IInviteMetadata.cs
  72. +65
    -0
      src/Discord.Net/Entities/Invites/Invite.cs
  73. +32
    -0
      src/Discord.Net/Entities/Invites/InviteMetadata.cs
  74. +0
    -0
      src/Discord.Net/Entities/Messages/Attachment.cs
  75. +0
    -0
      src/Discord.Net/Entities/Messages/Direction.cs
  76. +0
    -0
      src/Discord.Net/Entities/Messages/Embed.cs
  77. +0
    -0
      src/Discord.Net/Entities/Messages/EmbedProvider.cs
  78. +0
    -0
      src/Discord.Net/Entities/Messages/EmbedThumbnail.cs
  79. +1
    -1
      src/Discord.Net/Entities/Messages/IMessage.cs
  80. +1
    -1
      src/Discord.Net/Entities/Permissions/ChannelPermission.cs
  81. +151
    -0
      src/Discord.Net/Entities/Permissions/ChannelPermissions.cs
  82. +1
    -1
      src/Discord.Net/Entities/Permissions/GuildPermission.cs
  83. +68
    -62
      src/Discord.Net/Entities/Permissions/GuildPermissions.cs
  84. +0
    -0
      src/Discord.Net/Entities/Permissions/Overwrite.cs
  85. +62
    -53
      src/Discord.Net/Entities/Permissions/OverwritePermissions.cs
  86. +0
    -0
      src/Discord.Net/Entities/Permissions/PermValue.cs
  87. +0
    -0
      src/Discord.Net/Entities/Permissions/PermissionTarget.cs
  88. +159
    -0
      src/Discord.Net/Entities/Permissions/Permissions.cs
  89. +0
    -0
      src/Discord.Net/Entities/Roles/Color.cs
  90. +0
    -0
      src/Discord.Net/Entities/Roles/IRole.cs
  91. +31
    -0
      src/Discord.Net/Entities/Users/Connection.cs
  92. +22
    -0
      src/Discord.Net/Entities/Users/Game.cs
  93. +1
    -1
      src/Discord.Net/Entities/Users/IConnection.cs
  94. +2
    -5
      src/Discord.Net/Entities/Users/IGuildUser.cs
  95. +0
    -0
      src/Discord.Net/Entities/Users/ISelfUser.cs
  96. +2
    -1
      src/Discord.Net/Entities/Users/IUser.cs
  97. +0
    -0
      src/Discord.Net/Entities/Users/IVoiceState.cs.old
  98. +8
    -0
      src/Discord.Net/Entities/Users/StreamType.cs
  99. +0
    -0
      src/Discord.Net/Entities/Users/UserStatus.cs
  100. +46
    -0
      src/Discord.Net/EventExtensions.cs

+ 11
- 9
README.md View File

@@ -1,11 +1,14 @@
# Discord.Net v1.0.0-dev # Discord.Net v1.0.0-dev
[![NuGet Pre Release](https://img.shields.io/nuget/vpre/Discord.Net.svg?maxAge=2592000?style=plastic)](https://www.nuget.org/packages/Discord.Net) [![AppVeyor](https://img.shields.io/appveyor/ci/foxbot/discord-net.svg?maxAge=2592000?style=plastic)](https://ci.appveyor.com/project/foxbot/discord-net/) [![Discord](https://discordapp.com/api/servers/81384788765712384/widget.png)](https://discord.gg/0SBTUU1wZTYLhAAW)
[![Build status](https://ci.appveyor.com/api/projects/status/p0n69xhqgmoobycf/branch/master?svg=true)](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

+ 6
- 0
global.json View File

@@ -0,0 +1,6 @@
{
"projects": [ "src", "test" ],
"sdk": {
"version": "1.0.0-preview1-002702"
}
}

+ 7
- 1
src/Discord.Net/API/Common/Channel.cs View File

@@ -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")]


+ 14
- 0
src/Discord.Net/API/Common/Game.cs View File

@@ -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; }
}
}

+ 4
- 4
src/Discord.Net/API/Common/Overwrite.cs View File

@@ -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; }
} }
} }

+ 1
- 1
src/Discord.Net/API/Common/ReadState.cs View File

@@ -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; }
} }
} }

+ 2
- 2
src/Discord.Net/API/Common/Role.cs View File

@@ -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; }
} }


+ 2
- 2
src/Discord.Net/API/Common/UserGuild.cs View File

@@ -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; }
} }
} }

src/Discord.Net/API/DiscordAPIClient.cs
File diff suppressed because it is too large
View File


+ 24
- 0
src/Discord.Net/API/Gateway/GatewayOpCodes.cs View File

@@ -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
}
}

+ 12
- 0
src/Discord.Net/API/Gateway/GuildMembersChunkEvent.cs View File

@@ -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; }
}
}

+ 12
- 0
src/Discord.Net/API/Gateway/GuildRoleCreateEvent.cs View File

@@ -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; }
}
}

+ 12
- 0
src/Discord.Net/API/Gateway/GuildRoleUpdateEvent.cs View File

@@ -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; }
}
}

+ 17
- 0
src/Discord.Net/API/Gateway/IdentifyParams.cs View File

@@ -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; }
}
}

+ 40
- 0
src/Discord.Net/API/Gateway/ReadyEvent.cs View File

@@ -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; }
}
}

+ 14
- 0
src/Discord.Net/API/Gateway/RequestMembersParams.cs View File

@@ -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; }
}
}

+ 12
- 0
src/Discord.Net/API/Gateway/ResumeParams.cs View File

@@ -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; }
}
}

+ 10
- 0
src/Discord.Net/API/Gateway/ResumedEvent.cs View File

@@ -0,0 +1,10 @@
using Newtonsoft.Json;

namespace Discord.API.Gateway
{
public class ResumedEvent
{
[JsonProperty("heartbeat_interval")]
public int HeartbeatInterval { get; set; }
}
}

+ 14
- 0
src/Discord.Net/API/Gateway/TypingStartEvent.cs View File

@@ -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; }
}
}

+ 12
- 0
src/Discord.Net/API/Gateway/UpdateStatusParams.cs View File

@@ -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; }
}
}

+ 16
- 0
src/Discord.Net/API/Gateway/UpdateVoiceParams.cs View File

@@ -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; }
}
}

+ 14
- 0
src/Discord.Net/API/Gateway/VoiceServerUpdateEvent.cs View File

@@ -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; }
}
}

+ 7
- 0
src/Discord.Net/API/ImageAttribute.cs View File

@@ -0,0 +1,7 @@
using System;

namespace Discord.API
{
[AttributeUsage(AttributeTargets.Property)]
public class ImageAttribute : Attribute { }
}

+ 7
- 0
src/Discord.Net/API/Int53Attribute.cs View File

@@ -0,0 +1,7 @@
using System;

namespace Discord.API
{
[AttributeUsage(AttributeTargets.Property)]
public class Int53Attribute : Attribute { }
}

+ 10
- 7
src/Discord.Net/API/Optional.cs View File

@@ -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;
} }
} }

+ 2
- 3
src/Discord.Net/API/Rest/CreateGuildParams.cs View File

@@ -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; }
} }
} }

+ 2
- 2
src/Discord.Net/API/Rest/ModifyChannelPermissionsParams.cs View File

@@ -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; }
} }
} }

+ 1
- 1
src/Discord.Net/API/Rest/ModifyCurrentUserParams.cs View File

@@ -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; }
} }
} }

+ 1
- 1
src/Discord.Net/API/Rest/ModifyGuildChannelsParams.cs View File

@@ -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; }
} }


+ 2
- 2
src/Discord.Net/API/Rest/ModifyGuildParams.cs View File

@@ -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; }
} }
} }

+ 1
- 1
src/Discord.Net/API/Rest/ModifyGuildRoleParams.cs View File

@@ -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")]


+ 1
- 1
src/Discord.Net/API/Rest/ModifyGuildRolesParams.cs View File

@@ -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; }
} }
} }

+ 2
- 0
src/Discord.Net/API/Rest/ModifyVoiceChannelParams.cs View File

@@ -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; }
} }
} }

+ 18
- 0
src/Discord.Net/API/Voice/VoiceOpCodes.cs View File

@@ -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
}
}

+ 16
- 0
src/Discord.Net/API/WebSocketMessage.cs View File

@@ -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; }
}
}

+ 0
- 7
src/Discord.Net/Common/Entities/Guilds/IIntegrationAccount.cs View File

@@ -1,7 +0,0 @@
namespace Discord
{
public interface IIntegrationAccount : IEntity<string>
{
string Name { get; }
}
}

+ 0
- 10
src/Discord.Net/Common/Entities/Invites/IPublicInvite.cs View File

@@ -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; }
}
}

+ 0
- 136
src/Discord.Net/Common/Entities/Permissions/ChannelPermissions.cs View File

@@ -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);
}
}
}

+ 0
- 87
src/Discord.Net/Common/Entities/Permissions/PermissionUtilities.cs View File

@@ -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);
}
}

+ 0
- 8
src/Discord.Net/Common/Entities/Users/IDMUser.cs View File

@@ -1,8 +0,0 @@
namespace Discord
{
public interface IDMUser : IUser
{
/// <summary> Gets the private channel with this user. </summary>
IDMChannel Channel { get; }
}
}

+ 0
- 20
src/Discord.Net/Common/Events/SentRequestEventArgs.cs View File

@@ -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;
}
}
}

+ 0
- 13
src/Discord.Net/Common/Helpers/EventExtensions.cs View File

@@ -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);
}
}

+ 0
- 64
src/Discord.Net/Common/Helpers/PermissionHelper.cs View File

@@ -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;
}
}
}

+ 475
- 0
src/Discord.Net/ConcurrentHashSet.cs View File

@@ -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;
}
}
}
}

+ 10
- 0
src/Discord.Net/ConnectionState.cs View File

@@ -0,0 +1,10 @@
namespace Discord
{
public enum ConnectionState : byte
{
Disconnected,
Connecting,
Connected,
Disconnecting
}
}

src/Discord.Net/Common/Helpers/DateTimeHelper.cs → src/Discord.Net/DateTimeUtils.cs View File

@@ -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);
} }
} }

+ 0
- 223
src/Discord.Net/Discord.Net.csproj View File

@@ -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>

+ 19
- 0
src/Discord.Net/Discord.Net.xproj View File

@@ -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>

+ 5
- 2
src/Discord.Net/DiscordConfig.cs View File

@@ -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);
} }
} }

src/Discord.Net/Common/Entities/Channels/ChannelType.cs → src/Discord.Net/Entities/Channels/ChannelType.cs View File


src/Discord.Net/Common/Entities/Channels/IChannel.cs → src/Discord.Net/Entities/Channels/IChannel.cs View File

@@ -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);
} }

src/Discord.Net/Common/Entities/Channels/IDMChannel.cs → src/Discord.Net/Entities/Channels/IDMChannel.cs View File

@@ -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();

src/Discord.Net/Common/Entities/Channels/IGuildChannel.cs → src/Discord.Net/Entities/Channels/IGuildChannel.cs View File

@@ -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; }

src/Discord.Net/Common/Entities/Channels/IMessageChannel.cs → src/Discord.Net/Entities/Channels/IMessageChannel.cs View File

@@ -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>

src/Discord.Net/Common/Entities/Channels/ITextChannel.cs → src/Discord.Net/Entities/Channels/ITextChannel.cs View File


src/Discord.Net/Common/Entities/Channels/IVoiceChannel.cs → src/Discord.Net/Entities/Channels/IVoiceChannel.cs View File

@@ -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);

src/Discord.Net/Common/Entities/Guilds/Emoji.cs → src/Discord.Net/Entities/Guilds/Emoji.cs View File


src/Discord.Net/Common/Entities/Guilds/IGuild.cs → src/Discord.Net/Entities/Guilds/IGuild.cs View File

@@ -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();

src/Discord.Net/Common/Entities/Guilds/IGuildEmbed.cs → src/Discord.Net/Entities/Guilds/IGuildEmbed.cs View File


src/Discord.Net/Common/Entities/Guilds/IGuildIntegration.cs → src/Discord.Net/Entities/Guilds/IGuildIntegration.cs View File

@@ -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; }
} }
} }

src/Discord.Net/Common/Entities/Guilds/IUserGuild.cs → src/Discord.Net/Entities/Guilds/IUserGuild.cs View File


src/Discord.Net/Common/Entities/Guilds/IVoiceRegion.cs → src/Discord.Net/Entities/Guilds/IVoiceRegion.cs View File


+ 17
- 0
src/Discord.Net/Entities/Guilds/IntegrationAccount.cs View File

@@ -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})";
}
}

src/Discord.Net/Rest/Entities/Guilds/VoiceRegion.cs → src/Discord.Net/Entities/Guilds/VoiceRegion.cs View File

@@ -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" : "")})";
} }
} }

src/Discord.Net/Common/Entities/IDeletable.cs → src/Discord.Net/Entities/IDeletable.cs View File


src/Discord.Net/Common/Entities/IEntity.cs → src/Discord.Net/Entities/IEntity.cs View File


src/Discord.Net/Common/Entities/IMentionable.cs → src/Discord.Net/Entities/IMentionable.cs View File


src/Discord.Net/Common/Entities/ISnowflakeEntity.cs → src/Discord.Net/Entities/ISnowflakeEntity.cs View File


src/Discord.Net/Common/Entities/IUpdateable.cs → src/Discord.Net/Entities/IUpdateable.cs View File


src/Discord.Net/Common/Entities/Invites/IInvite.cs → src/Discord.Net/Entities/Invites/IInvite.cs View File

@@ -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; }

src/Discord.Net/Common/Entities/Invites/IGuildInvite.cs → src/Discord.Net/Entities/Invites/IInviteMetadata.cs View File

@@ -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; }
} }
} }

+ 65
- 0
src/Discord.Net/Entities/Invites/Invite.cs View File

@@ -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;
}
}

+ 32
- 0
src/Discord.Net/Entities/Invites/InviteMetadata.cs View File

@@ -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;
}
}
}

src/Discord.Net/Common/Entities/Messages/Attachment.cs → src/Discord.Net/Entities/Messages/Attachment.cs View File


src/Discord.Net/Common/Entities/Messages/Direction.cs → src/Discord.Net/Entities/Messages/Direction.cs View File


src/Discord.Net/Common/Entities/Messages/Embed.cs → src/Discord.Net/Entities/Messages/Embed.cs View File


src/Discord.Net/Common/Entities/Messages/EmbedProvider.cs → src/Discord.Net/Entities/Messages/EmbedProvider.cs View File


src/Discord.Net/Common/Entities/Messages/EmbedThumbnail.cs → src/Discord.Net/Entities/Messages/EmbedThumbnail.cs View File


src/Discord.Net/Common/Entities/Messages/IMessage.cs → src/Discord.Net/Entities/Messages/IMessage.cs View File

@@ -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
{ {

src/Discord.Net/Common/Entities/Permissions/ChannelPermission.cs → src/Discord.Net/Entities/Permissions/ChannelPermission.cs View File

@@ -1,6 +1,6 @@
namespace Discord namespace Discord
{ {
internal enum ChannelPermission : byte
public enum ChannelPermission : byte
{ {
//General //General
CreateInstantInvite = 0, CreateInstantInvite = 0,

+ 151
- 0
src/Discord.Net/Entities/Permissions/ChannelPermissions.cs View File

@@ -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())})";
}
}

src/Discord.Net/Common/Entities/Permissions/GuildPermission.cs → src/Discord.Net/Entities/Permissions/GuildPermission.cs View File

@@ -1,6 +1,6 @@
namespace Discord namespace Discord
{ {
internal enum GuildPermission : byte
public enum GuildPermission : byte
{ {
//General //General
CreateInstantInvite = 0, CreateInstantInvite = 0,

src/Discord.Net/Common/Entities/Permissions/GuildPermissions.cs → src/Discord.Net/Entities/Permissions/GuildPermissions.cs View File

@@ -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())})";
} }
} }

src/Discord.Net/Common/Entities/Permissions/Overwrite.cs → src/Discord.Net/Entities/Permissions/Overwrite.cs View File


src/Discord.Net/Common/Entities/Permissions/OverwritePermissions.cs → src/Discord.Net/Entities/Permissions/OverwritePermissions.cs View File

@@ -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())})";
} }
} }

src/Discord.Net/Common/Entities/Permissions/PermValue.cs → src/Discord.Net/Entities/Permissions/PermValue.cs View File


src/Discord.Net/Common/Entities/Permissions/PermissionTarget.cs → src/Discord.Net/Entities/Permissions/PermissionTarget.cs View File


+ 159
- 0
src/Discord.Net/Entities/Permissions/Permissions.cs View File

@@ -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;
}
}
}

src/Discord.Net/Common/Entities/Roles/Color.cs → src/Discord.Net/Entities/Roles/Color.cs View File


src/Discord.Net/Common/Entities/Roles/IRole.cs → src/Discord.Net/Entities/Roles/IRole.cs View File


+ 31
- 0
src/Discord.Net/Entities/Users/Connection.cs View File

@@ -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" : "")})";
}
}

+ 22
- 0
src/Discord.Net/Entities/Users/Game.cs View File

@@ -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;
}
}
}

src/Discord.Net/Common/Entities/Users/IConnection.cs → src/Discord.Net/Entities/Users/IConnection.cs View File

@@ -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; }
} }
} }

src/Discord.Net/Common/Entities/Users/IGuildUser.cs → src/Discord.Net/Entities/Users/IGuildUser.cs View File

@@ -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>

src/Discord.Net/Common/Entities/Users/ISelfUser.cs → src/Discord.Net/Entities/Users/ISelfUser.cs View File


src/Discord.Net/Common/Entities/Users/IUser.cs → src/Discord.Net/Entities/Users/IUser.cs View File

@@ -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();
} }

src/Discord.Net/Common/Entities/Users/IVoiceState.cs.old → src/Discord.Net/Entities/Users/IVoiceState.cs.old View File


+ 8
- 0
src/Discord.Net/Entities/Users/StreamType.cs View File

@@ -0,0 +1,8 @@
namespace Discord
{
public enum StreamType
{
NotStreaming = 0,
Twitch = 1
}
}

src/Discord.Net/Common/Entities/Users/UserStatus.cs → src/Discord.Net/Entities/Users/UserStatus.cs View File


+ 46
- 0
src/Discord.Net/EventExtensions.cs View File

@@ -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);
}
}
}
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save