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
[![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:
- [Discord.Net](https://www.nuget.org/packages/Discord.Net/)
- [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
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")]
public bool IsPrivate { get; set; }
[JsonProperty("last_message_id")]
public ulong LastMessageId { get; set; }
public ulong? LastMessageId { get; set; }

//GuildChannel
[JsonProperty("guild_id")]
@@ -23,10 +23,16 @@ namespace Discord.API
public int Position { get; set; }
[JsonProperty("permission_overwrites")]
public Overwrite[] PermissionOverwrites { get; set; }

//TextChannel
[JsonProperty("topic")]
public string Topic { get; set; }

//VoiceChannel
[JsonProperty("bitrate")]
public int Bitrate { get; set; }
[JsonProperty("user_limit")]
public int UserLimit { get; set; }

//DMChannel
[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; }
[JsonProperty("type")]
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")]
public int MentionCount { get; set; }
[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; }
[JsonProperty("position")]
public int? Position { get; set; }
[JsonProperty("permissions")]
public uint? Permissions { get; set; }
[JsonProperty("permissions"), Int53]
public ulong? Permissions { get; set; }
[JsonProperty("managed")]
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; }
[JsonProperty("owner")]
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.Diagnostics;

namespace Discord.API
{
//Based on https://github.com/dotnet/coreclr/blob/master/src/mscorlib/src/System/Nullable.cs
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public struct Optional<T> : IOptional
{
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
{
get
@@ -20,8 +22,6 @@ namespace Discord.API
/// <summary> Returns true if this value has been specified. </summary>
public bool IsSpecified { get; }

object IOptional.Value => _value;

/// <summary> Creates a new Parameter with the provided value. </summary>
public Optional(T value)
{
@@ -30,7 +30,7 @@ namespace Discord.API
}
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)
{
@@ -38,11 +38,14 @@ namespace Discord.API
if (other == null) return false;
return _value.Equals(other);
}

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

namespace Discord.API.Rest
@@ -11,7 +10,7 @@ namespace Discord.API.Rest
[JsonProperty("region")]
public string Region { get; set; }

[JsonProperty("icon"), JsonConverter(typeof(ImageConverter))]
[JsonProperty("icon"), Image]
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
{
[JsonProperty("allow")]
public Optional<uint> Allow { get; set; }
public Optional<ulong> Allow { get; set; }
[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; }
[JsonProperty("new_password")]
public Optional<string> NewPassword { get; set; }
[JsonProperty("avatar"), JsonConverter(typeof(ImageConverter))]
[JsonProperty("avatar"), Image]
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
{
[JsonProperty("id")]
public Optional<ulong> Id { get; set; }
public ulong Id { get; set; }
[JsonProperty("position")]
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; }
[JsonProperty("afk_timeout")]
public Optional<int> AFKTimeout { get; set; }
[JsonProperty("icon"), JsonConverter(typeof(ImageConverter))]
[JsonProperty("icon"), Image]
public Optional<Stream> Icon { get; set; }
[JsonProperty("owner_id")]
public Optional<GuildMember> Owner { get; set; }
[JsonProperty("splash"), JsonConverter(typeof(ImageConverter))]
[JsonProperty("splash"), Image]
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")]
public Optional<string> Name { get; set; }
[JsonProperty("permissions")]
public Optional<uint> Permissions { get; set; }
public Optional<ulong> Permissions { get; set; }
[JsonProperty("position")]
public Optional<int> Position { get; set; }
[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
{
[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")]
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
{
internal static class DateTimeHelper
internal static class DateTimeUtils
{
private const ulong EpochTicks = 621355968000000000UL;
private const ulong DiscordEpochMillis = 1420070400000UL;

public static DateTime FromEpochMilliseconds(ulong value)
=> new DateTime((long)(value * TimeSpan.TicksPerMillisecond + EpochTicks), DateTimeKind.Utc);
@@ -12,6 +13,6 @@ namespace Discord
=> new DateTime((long)(value * TimeSpan.TicksPerSecond + EpochTicks), DateTimeKind.Utc);

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
{
//TODO: Add socket config items in their own class

public class DiscordConfig
{
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 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 CDNUrl = "https://cdn.discordapp.com/";
@@ -26,6 +29,6 @@ namespace Discord
public LogSeverity LogLevel { get; set; } = LogSeverity.Info;

/// <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>
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>
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
{
/// <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>
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="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>
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>
Task<IEnumerable<IGuildInvite>> GetInvites();
Task<IEnumerable<IInviteMetadata>> GetInvites();

/// <summary> Gets a collection of permission overwrites for this channel. </summary>
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
{
/// <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>
Task<IEnumerable<IMessage>> GetMessages(int limit = DiscordConfig.MaxMessagesPerBatch);
/// <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>
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>
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);

/// <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>
/// <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="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>
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>
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 ExpireGracePeriod { get; }
DateTime SyncedAt { get; }
IntegrationAccount Account { get; }

IGuild Guild { get; }
IUser User { 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
{
/// <inheritdoc />
@@ -27,6 +29,7 @@ namespace Discord.Rest
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
{
public interface IInvite : IEntity<string>
public interface IInvite : IEntity<string>, IDeletable
{
/// <summary> Gets the unique identifier for this invite. </summary>
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
{
public interface IGuildInvite : IDeletable, IInvite
public interface IInviteMetadata : IInvite
{
/// <summary> Returns true if this invite was revoked. </summary>
bool IsRevoked { get; }
@@ -12,8 +12,5 @@
int? MaxUses { get; }
/// <summary> Gets the amount of times this invite has been used. </summary>
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.Collections.Generic;
using System.Threading.Tasks;
using Discord.API.Rest;
using System.Collections.Generic;

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
{
internal enum ChannelPermission : byte
public enum ChannelPermission : byte
{
//General
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
{
internal enum GuildPermission : byte
public enum GuildPermission : byte
{
//General
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
{
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public struct GuildPermissions
{
/// <summary> Gets a blank GuildPermissions that grants no permissions. </summary>
public static readonly GuildPermissions None = new GuildPermissions();
/// <summary> Gets a GuildPermissions that grants all permissions. </summary>
#if CSHARP7
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>
public uint RawValue { get; }
public ulong RawValue { get; }

/// <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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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? readMessages = null, bool? sendMessages = null, bool? sendTTSMessages = null, bool? manageMessages = 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? 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;
}
@@ -125,21 +132,20 @@ namespace Discord
=> new GuildPermissions(RawValue, createInstantInvite, manageRoles, kickMembers, banMembers, manageChannels, manageGuild, readMessages,
sendMessages, sendTTSMessages, manageMessages, embedLinks, attachFiles, mentionEveryone, connect, speak, muteMembers, deafenMembers,
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 (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.Collections.Generic;
using System.Diagnostics;

namespace Discord
{
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public struct OverwritePermissions
{
/// <summary> Gets a blank OverwritePermissions that inherits all permissions. </summary>
@@ -15,77 +17,77 @@ namespace Discord
=> new OverwritePermissions(0, ChannelPermissions.All(channel).RawValue);

/// <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>
public uint DenyValue { get; }
public ulong DenyValue { get; }

/// <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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
public OverwritePermissions(uint allowValue, uint denyValue)
public OverwritePermissions(ulong allowValue, ulong denyValue)
{
AllowValue = allowValue;
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? embedLinks = null, PermValue? attachFiles = null, PermValue? readMessageHistory = null, PermValue? mentionEveryone = null,
PermValue? connect = null, PermValue? speak = null, PermValue? muteMembers = null, PermValue? deafenMembers = 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;
DenyValue = denyValue;
@@ -111,25 +113,32 @@ namespace Discord
embedLinks, attachFiles, readMessageHistory, mentionEveryone, connect, speak, muteMembers, deafenMembers,
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 (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; }
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; }
/// <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; }
/// <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>
GuildPermissions GetGuildPermissions();
/// <summary> Gets the channel-level permissions granted to this user for a given channel. </summary>
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>
Task Kick();
/// <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>
string AvatarUrl { get; }
/// <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>
ushort Discriminator { get; }
/// <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>
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>
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