diff --git a/.gitignore b/.gitignore
index a16fc009f..2fcef09e8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -197,3 +197,4 @@ FakesAssemblies/
#Custom
Credentials.cs
+project.lock.json
\ No newline at end of file
diff --git a/Discord.Net.sln b/Discord.Net.sln
index 0eac29c74..1d7cbfd25 100644
--- a/Discord.Net.sln
+++ b/Discord.Net.sln
@@ -3,17 +3,28 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.23107.0
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net", "Discord.Net\Discord.Net.csproj", "{8D23F61B-723C-4966-859D-1119B28BCF19}"
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{8D7989F0-66CE-4DBB-8230-D8C811E9B1D7}"
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{1DDC89B5-2A88-45E5-A743-7A43E6B5C4B3}"
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{6317A2E6-8E36-4C3E-949B-3F10EC888AB9}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{1BE8AF3F-3CFD-433F-A380-D294A4F617C1}"
ProjectSection(SolutionItems) = preProject
- .gitattributes = .gitattributes
- .gitignore = .gitignore
- LICENSE = LICENSE
- README.md = README.md
+ global.json = global.json
EndProjectSection
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net.Tests", "Discord.Net.Tests\Discord.Net.Tests.csproj", "{855D6B1D-847B-42DA-BE6A-23683EA89511}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net.Tests", "test\Discord.Net.Tests\Discord.Net.Tests.csproj", "{855D6B1D-847B-42DA-BE6A-23683EA89511}"
+EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Discord.Net", "src\Discord.Net\Discord.Net.xproj", "{ACFB060B-EC8A-4926-B293-04C01E17EE23}"
+EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Discord.Net.Commands", "src\Discord.Net.Commands\Discord.Net.Commands.xproj", "{19793545-EF89-48F4-8100-3EBAAD0A9141}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "net45", "net45", "{B47C4063-C4EB-46AA-886D-B868DA1BF0A0}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net", "src\Discord.Net.Net45\Discord.Net.csproj", "{8D71A857-879A-4A10-859E-5FF824ED6688}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net.Commands", "src\Discord.Net.Commands.Net45\Discord.Net.Commands.csproj", "{1B5603B4-6F8F-4289-B945-7BAAE523D740}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dotnet", "dotnet", "{EA68EBE2-51C8-4440-9EF7-D633C90A5D35}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -21,16 +32,37 @@ Global
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {8D23F61B-723C-4966-859D-1119B28BCF19}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {8D23F61B-723C-4966-859D-1119B28BCF19}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {8D23F61B-723C-4966-859D-1119B28BCF19}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {8D23F61B-723C-4966-859D-1119B28BCF19}.Release|Any CPU.Build.0 = Release|Any CPU
{855D6B1D-847B-42DA-BE6A-23683EA89511}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{855D6B1D-847B-42DA-BE6A-23683EA89511}.Debug|Any CPU.Build.0 = Debug|Any CPU
{855D6B1D-847B-42DA-BE6A-23683EA89511}.Release|Any CPU.ActiveCfg = Release|Any CPU
{855D6B1D-847B-42DA-BE6A-23683EA89511}.Release|Any CPU.Build.0 = Release|Any CPU
+ {ACFB060B-EC8A-4926-B293-04C01E17EE23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {ACFB060B-EC8A-4926-B293-04C01E17EE23}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {ACFB060B-EC8A-4926-B293-04C01E17EE23}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {ACFB060B-EC8A-4926-B293-04C01E17EE23}.Release|Any CPU.Build.0 = Release|Any CPU
+ {19793545-EF89-48F4-8100-3EBAAD0A9141}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {19793545-EF89-48F4-8100-3EBAAD0A9141}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {19793545-EF89-48F4-8100-3EBAAD0A9141}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {19793545-EF89-48F4-8100-3EBAAD0A9141}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8D71A857-879A-4A10-859E-5FF824ED6688}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8D71A857-879A-4A10-859E-5FF824ED6688}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8D71A857-879A-4A10-859E-5FF824ED6688}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8D71A857-879A-4A10-859E-5FF824ED6688}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1B5603B4-6F8F-4289-B945-7BAAE523D740}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1B5603B4-6F8F-4289-B945-7BAAE523D740}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1B5603B4-6F8F-4289-B945-7BAAE523D740}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1B5603B4-6F8F-4289-B945-7BAAE523D740}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {855D6B1D-847B-42DA-BE6A-23683EA89511} = {6317A2E6-8E36-4C3E-949B-3F10EC888AB9}
+ {ACFB060B-EC8A-4926-B293-04C01E17EE23} = {EA68EBE2-51C8-4440-9EF7-D633C90A5D35}
+ {19793545-EF89-48F4-8100-3EBAAD0A9141} = {EA68EBE2-51C8-4440-9EF7-D633C90A5D35}
+ {B47C4063-C4EB-46AA-886D-B868DA1BF0A0} = {8D7989F0-66CE-4DBB-8230-D8C811E9B1D7}
+ {8D71A857-879A-4A10-859E-5FF824ED6688} = {B47C4063-C4EB-46AA-886D-B868DA1BF0A0}
+ {1B5603B4-6F8F-4289-B945-7BAAE523D740} = {B47C4063-C4EB-46AA-886D-B868DA1BF0A0}
+ {EA68EBE2-51C8-4440-9EF7-D633C90A5D35} = {8D7989F0-66CE-4DBB-8230-D8C811E9B1D7}
+ EndGlobalSection
EndGlobal
diff --git a/Discord.Net/BuildNuget.cmd b/Discord.Net/BuildNuget.cmd
deleted file mode 100644
index d72e6c121..000000000
--- a/Discord.Net/BuildNuget.cmd
+++ /dev/null
@@ -1,2 +0,0 @@
-nuget pack Discord.Net.csproj -Prop Configuration=Release
-pause
\ No newline at end of file
diff --git a/Discord.Net/Discord.Net.csproj b/Discord.Net/Discord.Net.csproj
deleted file mode 100644
index 9325d90be..000000000
--- a/Discord.Net/Discord.Net.csproj
+++ /dev/null
@@ -1,89 +0,0 @@
-
-
-
-
- Release
- AnyCPU
- {8D23F61B-723C-4966-859D-1119B28BCF19}
- Library
- Properties
- Discord
- Discord.Net
- v4.5
- 512
-
-
-
- true
- full
- false
- bin\Debug\
- DEBUG;TRACE
- prompt
- 4
- false
-
-
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
- false
-
-
-
- ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll
- True
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Designer
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Discord.Net/Discord.Net.nuspec b/Discord.Net/Discord.Net.nuspec
deleted file mode 100644
index 3ff7640dd..000000000
--- a/Discord.Net/Discord.Net.nuspec
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
- $id$
- $version$
- $title$
- $author$
- $author$
- http://opensource.org/licenses/MIT
- https://github.com/RogueException/Discord.Net
- false
- $description$
-
- Copyright 2015
- Discord DiscordApp
-
-
\ No newline at end of file
diff --git a/global.json b/global.json
new file mode 100644
index 000000000..4a056d884
--- /dev/null
+++ b/global.json
@@ -0,0 +1,8 @@
+{
+ "projects": [ "src" ],
+ "sdk": {
+ "version": "1.0.0-beta6",
+ "architecture": "x64",
+ "runtime": "coreclr"
+ }
+}
\ No newline at end of file
diff --git a/src/Discord.Net.Commands.Net45/Discord.Net.Commands.csproj b/src/Discord.Net.Commands.Net45/Discord.Net.Commands.csproj
new file mode 100644
index 000000000..bf7a0d06d
--- /dev/null
+++ b/src/Discord.Net.Commands.Net45/Discord.Net.Commands.csproj
@@ -0,0 +1,67 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {1B5603B4-6F8F-4289-B945-7BAAE523D740}
+ Library
+ Properties
+ Discord.Net
+ Discord.Net.Commands
+ 512
+ v4.5
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ true
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ true
+
+
+
+
+
+
+
+ {8d71a857-879a-4a10-859e-5ff824ed6688}
+ Discord.Net
+
+
+
+
+ CommandBuilder.cs
+
+
+ CommandParser.cs
+
+
+ DiscordBotClient.cs
+
+
+ DiscordBotClient.Events.cs
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Discord.Net/Properties/AssemblyInfo.cs b/src/Discord.Net.Commands.Net45/Properties/AssemblyInfo.cs
similarity index 57%
rename from Discord.Net/Properties/AssemblyInfo.cs
rename to src/Discord.Net.Commands.Net45/Properties/AssemblyInfo.cs
index 8c94c0232..e8e45ec9a 100644
--- a/Discord.Net/Properties/AssemblyInfo.cs
+++ b/src/Discord.Net.Commands.Net45/Properties/AssemblyInfo.cs
@@ -1,13 +1,17 @@
using System.Reflection;
+using System.Runtime.InteropServices;
[assembly: AssemblyTitle("Discord.Net")]
[assembly: AssemblyDescription("An unofficial .Net API wrapper for the Discord client.")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("RogueException")]
[assembly: AssemblyProduct("Discord.Net")]
-[assembly: AssemblyCopyright("Copyright © RogueException 2015")]
+[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("0.3.2.0")]
-[assembly: AssemblyFileVersion("0.3.2.0")]
+[assembly: ComVisible(false)]
+[assembly: Guid("76ea00e6-ea24-41e1-acb2-639c0313fa80")]
+
+[assembly: AssemblyVersion("0.2.0.0")]
+[assembly: AssemblyFileVersion("0.2.0.0")]
diff --git a/src/Discord.Net.Commands/CommandBuilder.cs b/src/Discord.Net.Commands/CommandBuilder.cs
new file mode 100644
index 000000000..78a505ea9
--- /dev/null
+++ b/src/Discord.Net.Commands/CommandBuilder.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Threading.Tasks;
+
+namespace Discord
+{
+ public sealed class CommandBuilder
+ {
+ private readonly DiscordBotClient _client;
+ private readonly string _prefix;
+ private readonly bool _useWhitelist;
+
+ public CommandBuilder(DiscordBotClient client, string prefix, bool useWhitelist = false)
+ {
+ _client = client;
+ _prefix = prefix;
+ _useWhitelist = useWhitelist;
+ }
+
+ public void AddCommandGroup(string cmd, Action config, bool useWhitelist = false)
+ {
+ config(new CommandBuilder(_client, _prefix + ' ' + cmd, useWhitelist));
+ }
+ public void AddCommand(string cmd, int minArgs, int maxArgs, Action handler, bool? useWhitelist = null)
+ {
+ AddCommand(cmd, minArgs, maxArgs, e => { handler(e); return null; }, useWhitelist);
+ }
+ public void AddCommand(string cmd, int minArgs, int maxArgs, Func handler, bool? useWhitelist = null)
+ {
+ _client.AddCommand(cmd != "" ? _prefix + ' ' + cmd : _prefix, minArgs, maxArgs, handler, useWhitelist ?? _useWhitelist);
+ }
+ }
+}
diff --git a/src/Discord.Net.Commands/CommandParser.cs b/src/Discord.Net.Commands/CommandParser.cs
new file mode 100644
index 000000000..ef854fea2
--- /dev/null
+++ b/src/Discord.Net.Commands/CommandParser.cs
@@ -0,0 +1,154 @@
+using System.Collections.Generic;
+
+namespace Discord
+{
+ public static class CommandParser
+ {
+ private enum CommandParserPart
+ {
+ None,
+ CommandName,
+ Parameter,
+ QuotedParameter,
+ DoubleQuotedParameter
+ }
+
+ public static bool Parse(string input, out string command, out string[] args)
+ {
+ return Parse(input, out command, out args, true);
+ }
+ public static bool ParseArgs(string input, out string[] args)
+ {
+ string ignored;
+ return Parse(input, out ignored, out args, false);
+ }
+
+ private static bool Parse(string input, out string command, out string[] args, bool parseCommand)
+ {
+ CommandParserPart currentPart = parseCommand ? CommandParserPart.CommandName : CommandParserPart.None;
+ int startPosition = 0;
+ int endPosition = 0;
+ int inputLength = input.Length;
+ bool isEscaped = false;
+ List argList = new List();
+
+ command = null;
+ args = null;
+
+ if (input == "")
+ return false;
+
+ while (endPosition < inputLength)
+ {
+ char currentChar = input[endPosition++];
+ if (isEscaped)
+ isEscaped = false;
+ else if (currentChar == '\\')
+ isEscaped = true;
+
+ switch (currentPart)
+ {
+ case CommandParserPart.CommandName:
+ if ((!isEscaped && currentChar == ' ') || endPosition >= inputLength)
+ {
+ int length = (currentChar == ' ' ? endPosition - 1 : endPosition) - startPosition;
+ string temp = input.Substring(startPosition, length);
+ if (temp == "")
+ startPosition = endPosition;
+ else
+ {
+ currentPart = CommandParserPart.None;
+ command = temp;
+ startPosition = endPosition;
+ }
+ }
+ break;
+ case CommandParserPart.None:
+ if ((!isEscaped && currentChar == '\"'))
+ {
+ currentPart = CommandParserPart.DoubleQuotedParameter;
+ startPosition = endPosition;
+ }
+ else if ((!isEscaped && currentChar == '\''))
+ {
+ currentPart = CommandParserPart.QuotedParameter;
+ startPosition = endPosition;
+ }
+ else if ((!isEscaped && currentChar == ' ') || endPosition >= inputLength)
+ {
+ int length = (currentChar == ' ' ? endPosition - 1 : endPosition) - startPosition;
+ string temp = input.Substring(startPosition, length);
+ if (temp == "")
+ startPosition = endPosition;
+ else
+ {
+ currentPart = CommandParserPart.None;
+ argList.Add(temp);
+ startPosition = endPosition;
+ }
+ }
+ break;
+ case CommandParserPart.QuotedParameter:
+ if ((!isEscaped && currentChar == '\''))
+ {
+ string temp = input.Substring(startPosition, endPosition - startPosition - 1);
+ currentPart = CommandParserPart.None;
+ argList.Add(temp);
+ startPosition = endPosition;
+ }
+ else if (endPosition >= inputLength)
+ return false;
+ break;
+ case CommandParserPart.DoubleQuotedParameter:
+ if ((!isEscaped && currentChar == '\"'))
+ {
+ string temp = input.Substring(startPosition, endPosition - startPosition - 1);
+ currentPart = CommandParserPart.None;
+ argList.Add(temp);
+ startPosition = endPosition;
+ }
+ else if (endPosition >= inputLength)
+ return false;
+ break;
+ }
+ }
+
+ if (parseCommand && (command == null || command == ""))
+ return false;
+
+ args = argList.ToArray();
+ return true;
+ }
+
+ public static bool ArgsEqual(string[] args, int expected)
+ {
+ return args.Length == expected;
+ }
+ public static bool ArgsAtLeast(string[] args, int expected)
+ {
+ return args.Length >= expected;
+ }
+ public static bool ArgsAtMost(string[] args, int expected)
+ {
+ return args.Length <= expected;
+ }
+ public static bool ArgsIn(string[] args, params int[] expected)
+ {
+ int count = args.Length;
+ for (int i = 0; i < expected.Length; i++)
+ {
+ if (count == expected[i])
+ return true;
+ }
+ return false;
+ }
+ public static bool ArgsBetween(string[] args, int min, int max)
+ {
+ return args.Length >= min && args.Length <= max;
+ }
+ public static bool NoArgs(string[] args, params int[] expected)
+ {
+ return args.Length == 0;
+ }
+ }
+}
diff --git a/src/Discord.Net.Commands/Discord.Net.Commands.xproj b/src/Discord.Net.Commands/Discord.Net.Commands.xproj
new file mode 100644
index 000000000..e6d1163ef
--- /dev/null
+++ b/src/Discord.Net.Commands/Discord.Net.Commands.xproj
@@ -0,0 +1,21 @@
+
+
+
+ 14.0
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+
+
+
+ 19793545-ef89-48f4-8100-3ebaad0a9141
+ Discord.Net.Commands
+ ..\..\artifacts\obj\$(MSBuildProjectName)
+ ..\..\artifacts\bin\$(MSBuildProjectName)\
+
+
+ 2.0
+
+
+ True
+
+
+
\ No newline at end of file
diff --git a/src/Discord.Net.Commands/DiscordBotClient.Events.cs b/src/Discord.Net.Commands/DiscordBotClient.Events.cs
new file mode 100644
index 000000000..edddc4953
--- /dev/null
+++ b/src/Discord.Net.Commands/DiscordBotClient.Events.cs
@@ -0,0 +1,50 @@
+using System;
+
+namespace Discord
+{
+ public partial class DiscordBotClient : DiscordClient
+ {
+ public class CommandEventArgs
+ {
+ public readonly Message Message;
+ public readonly Command Command;
+ public readonly string[] Args;
+
+ public User User => Message.User;
+ public string UserId => Message.UserId;
+ public Channel Channel => Message.Channel;
+ public string ChannelId => Message.ChannelId;
+ public Server Server => Message.Channel.Server;
+ public string ServerId => Message.Channel.ServerId;
+
+ public CommandEventArgs(Message message, Command command, string[] args)
+ {
+ Message = message;
+ Command = command;
+ Args = args;
+ }
+ }
+ public class CommandErrorEventArgs : CommandEventArgs
+ {
+ public readonly Exception Exception;
+ public CommandErrorEventArgs(Message message, Command command, string[] args, Exception ex)
+ : base(message, command, args)
+ {
+ Exception = ex;
+ }
+ }
+
+ public event EventHandler RanCommand;
+ private void RaiseRanCommand(CommandEventArgs args)
+ {
+ if (RanCommand != null)
+ RanCommand(this, args);
+ }
+ public event EventHandler CommandError;
+ private void RaiseCommandError(Message msg, Command command, string[] args, Exception ex)
+ {
+ if (CommandError != null)
+ CommandError(this, new CommandErrorEventArgs(msg, command, args, ex));
+ }
+ }
+}
diff --git a/src/Discord.Net.Commands/DiscordBotClient.cs b/src/Discord.Net.Commands/DiscordBotClient.cs
new file mode 100644
index 000000000..35d0f4c4b
--- /dev/null
+++ b/src/Discord.Net.Commands/DiscordBotClient.cs
@@ -0,0 +1,151 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace Discord
+{
+ public sealed class Command
+ {
+ public readonly string[] Text;
+ public readonly int MinArgs, MaxArgs;
+ public readonly bool UseWhitelist;
+ internal readonly Func Handler;
+
+ public Command(string[] text, int minArgs, int maxArgs, bool useWhitelist, Func handler)
+ {
+ Text = text;
+ MinArgs = minArgs;
+ MaxArgs = maxArgs;
+ UseWhitelist = useWhitelist;
+ Handler = handler;
+ }
+ }
+
+ ///
+ /// A Discord.Net client with extensions for handling common bot operations like text commands.
+ ///
+ public partial class DiscordBotClient : DiscordClient
+ {
+ private List _commands;
+ private List _whitelist;
+
+ public IEnumerable Commands => _commands;
+
+ public char CommandChar { get; set; }
+ public bool UseCommandChar { get; set; }
+ public bool RequireCommandCharInPublic { get; set; }
+ public bool RequireCommandCharInPrivate { get; set; }
+ public bool AlwaysUseWhitelist { get; set; }
+
+ public DiscordBotClient()
+ {
+ _commands = new List();
+ _whitelist = new List();
+
+ CommandChar = '~';
+ RequireCommandCharInPublic = true;
+ RequireCommandCharInPrivate = true;
+ AlwaysUseWhitelist = false;
+
+ MessageCreated += async (s, e) =>
+ {
+ //Ignore messages from ourselves
+ if (e.Message.UserId == UserId)
+ return;
+
+ //Check the global whitelist
+ if (AlwaysUseWhitelist && !_whitelist.Contains(e.Message.UserId))
+ return;
+
+ //Check for the command character
+ string msg = e.Message.Text;
+ if (UseCommandChar)
+ {
+ if (msg.Length == 0)
+ return;
+ bool isPrivate = e.Message.Channel.IsPrivate;
+ bool hasCommandChar = msg[0] == CommandChar;
+ if (hasCommandChar)
+ msg = msg.Substring(1);
+ if (!isPrivate && RequireCommandCharInPublic && !hasCommandChar)
+ return;
+ if (isPrivate && RequireCommandCharInPrivate && !hasCommandChar)
+ return;
+ }
+
+ string[] args;
+ if (!CommandParser.ParseArgs(msg, out args))
+ return;
+
+ for (int i = 0; i < _commands.Count; i++)
+ {
+ Command cmd = _commands[i];
+
+ //Check Command Parts
+ if (args.Length < cmd.Text.Length)
+ continue;
+
+ bool isValid = true;
+ for (int j = 0; j < cmd.Text.Length; j++)
+ {
+ if (!string.Equals(args[j], cmd.Text[j], StringComparison.OrdinalIgnoreCase))
+ {
+ isValid = false;
+ break;
+ }
+ }
+ if (!isValid)
+ continue;
+
+ //Check Whitelist
+ if (cmd.UseWhitelist && !_whitelist.Contains(e.Message.UserId))
+ continue;
+
+ //Check Arg Count
+ int argCount = args.Length - cmd.Text.Length;
+ if (argCount < cmd.MinArgs || argCount > cmd.MaxArgs)
+ continue;
+
+ //Run Command
+ string[] newArgs = new string[argCount];
+ for (int j = 0; j < newArgs.Length; j++)
+ newArgs[j] = args[j + cmd.Text.Length];
+
+ var eventArgs = new CommandEventArgs(e.Message, cmd, newArgs);
+ RaiseRanCommand(eventArgs);
+ try
+ {
+ var task = cmd.Handler(eventArgs);
+ if (task != null)
+ await task;
+ }
+ catch (Exception ex)
+ {
+ RaiseCommandError(e.Message, cmd, newArgs, ex);
+ }
+ break;
+ }
+ };
+ }
+
+ public void AddCommandGroup(string cmd, Action config, bool useWhitelist = false)
+ {
+ config(new CommandBuilder(this, cmd, useWhitelist));
+ }
+ public void AddCommand(string cmd, int minArgs, int maxArgs, Action handler, bool useWhitelist = false)
+ {
+ AddCommand(cmd, minArgs, maxArgs, e => { handler(e); return null; }, useWhitelist);
+ }
+ public void AddCommand(string cmd, int minArgs, int maxArgs, Func handler, bool useWhitelist = false)
+ {
+ _commands.Add(new Command(cmd.Split(' '), minArgs, maxArgs, useWhitelist, handler));
+ }
+
+ public void AddWhitelist(User user)
+ => AddWhitelist(user.Id);
+ public void AddWhitelist(string userId)
+ {
+ _whitelist.Add(userId);
+ }
+ }
+}
diff --git a/src/Discord.Net.Commands/project.json b/src/Discord.Net.Commands/project.json
new file mode 100644
index 000000000..b2521d6af
--- /dev/null
+++ b/src/Discord.Net.Commands/project.json
@@ -0,0 +1,26 @@
+{
+ "version": "0.2.0-*",
+ "description": "A small Discord.Net extension to make bot creation easier.",
+ "authors": [ "RogueException" ],
+ "tags": [ "discord", "discordapp" ],
+ "projectUrl": "https://github.com/RogueException/Discord.Net",
+ "licenseUrl": "http://opensource.org/licenses/MIT",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/RogueException/Discord.Net"
+ },
+ "compilationOptions": {
+ "warningsAsErrors": true
+ },
+ "dependencies": {
+ "Discord.Net": ""
+ },
+ "frameworks": {
+ "dotnet": {
+ "dependencies": {
+ "System.Runtime": "4.0.20",
+ "Microsoft.CSharp": "4.0.0"
+ }
+ }
+ }
+}
diff --git a/src/Discord.Net.Net45/Discord.Net.csproj b/src/Discord.Net.Net45/Discord.Net.csproj
new file mode 100644
index 000000000..157eae0e7
--- /dev/null
+++ b/src/Discord.Net.Net45/Discord.Net.csproj
@@ -0,0 +1,121 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {8D71A857-879A-4A10-859E-5FF824ED6688}
+ Library
+ Properties
+ Discord.Net
+ Discord.Net
+ 512
+ v4.5
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ true
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ true
+
+
+
+ ..\..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll
+ True
+
+
+
+
+
+
+
+
+ API\DiscordAPI.cs
+
+
+ API\Endpoints.cs
+
+
+ API\Models\APIRequests.cs
+
+
+ API\Models\APIResponses.cs
+
+
+ API\Models\Common.cs
+
+
+ API\Models\WebSocketCommands.cs
+
+
+ API\Models\WebSocketEvents.cs
+
+
+ Channel.cs
+
+
+ ChannelTypes.cs
+
+
+ DiscordClient.cs
+
+
+ DiscordClient.Events.cs
+
+
+ DiscordWebSocket.cs
+
+
+ DiscordWebSocket.Events.cs
+
+
+ Helpers\AsyncCache.cs
+
+
+ Helpers\Http.cs
+
+
+ Invite.cs
+
+
+ Membership.cs
+
+
+ Message.cs
+
+
+ Regions.cs
+
+
+ Role.cs
+
+
+ Server.cs
+
+
+ User.cs
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Discord.Net.Net45/Properties/AssemblyInfo.cs b/src/Discord.Net.Net45/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..3d45d6d43
--- /dev/null
+++ b/src/Discord.Net.Net45/Properties/AssemblyInfo.cs
@@ -0,0 +1,17 @@
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+[assembly: AssemblyTitle("Discord.Net")]
+[assembly: AssemblyDescription("An unofficial .Net API wrapper for the Discord client.")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("RogueException")]
+[assembly: AssemblyProduct("Discord.Net")]
+[assembly: AssemblyCopyright("Copyright © 2015")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+[assembly: ComVisible(false)]
+[assembly: Guid("76ea00e6-ea24-41e1-acb2-639c0313fa80")]
+
+[assembly: AssemblyVersion("0.3.3.0")]
+[assembly: AssemblyFileVersion("0.3.3.0")]
diff --git a/Discord.Net/packages.config b/src/Discord.Net.Net45/packages.config
similarity index 83%
rename from Discord.Net/packages.config
rename to src/Discord.Net.Net45/packages.config
index 64b5d8efe..505e58836 100644
--- a/Discord.Net/packages.config
+++ b/src/Discord.Net.Net45/packages.config
@@ -1,4 +1,4 @@
-
+
\ No newline at end of file
diff --git a/Discord.Net/API/DiscordAPI.cs b/src/Discord.Net/API/DiscordAPI.cs
similarity index 100%
rename from Discord.Net/API/DiscordAPI.cs
rename to src/Discord.Net/API/DiscordAPI.cs
diff --git a/Discord.Net/API/Endpoints.cs b/src/Discord.Net/API/Endpoints.cs
similarity index 100%
rename from Discord.Net/API/Endpoints.cs
rename to src/Discord.Net/API/Endpoints.cs
diff --git a/Discord.Net/API/Models/ApiRequests.cs b/src/Discord.Net/API/Models/APIRequests.cs
similarity index 100%
rename from Discord.Net/API/Models/ApiRequests.cs
rename to src/Discord.Net/API/Models/APIRequests.cs
diff --git a/Discord.Net/API/Models/APIResponses.cs b/src/Discord.Net/API/Models/APIResponses.cs
similarity index 100%
rename from Discord.Net/API/Models/APIResponses.cs
rename to src/Discord.Net/API/Models/APIResponses.cs
diff --git a/Discord.Net/API/Models/Common.cs b/src/Discord.Net/API/Models/Common.cs
similarity index 100%
rename from Discord.Net/API/Models/Common.cs
rename to src/Discord.Net/API/Models/Common.cs
diff --git a/Discord.Net/API/Models/WebSocketCommands.cs b/src/Discord.Net/API/Models/WebSocketCommands.cs
similarity index 100%
rename from Discord.Net/API/Models/WebSocketCommands.cs
rename to src/Discord.Net/API/Models/WebSocketCommands.cs
diff --git a/Discord.Net/API/Models/WebSocketEvents.cs b/src/Discord.Net/API/Models/WebSocketEvents.cs
similarity index 100%
rename from Discord.Net/API/Models/WebSocketEvents.cs
rename to src/Discord.Net/API/Models/WebSocketEvents.cs
diff --git a/Discord.Net/Channel.cs b/src/Discord.Net/Channel.cs
similarity index 89%
rename from Discord.Net/Channel.cs
rename to src/Discord.Net/Channel.cs
index 44fe5e231..8ab723969 100644
--- a/Discord.Net/Channel.cs
+++ b/src/Discord.Net/Channel.cs
@@ -11,7 +11,7 @@ namespace Discord
public string Id { get; }
private string _name;
- public string Name { get { return !IsPrivate ? _name : '@' + Recipient.Name; } internal set { _name = value; } }
+ public string Name { get { return !IsPrivate ? $"#{_name}" : $"@{Recipient.Name}"; } internal set { _name = value; } }
public bool IsPrivate { get; }
public string Type { get; internal set; }
diff --git a/Discord.Net/ChannelTypes.cs b/src/Discord.Net/ChannelTypes.cs
similarity index 100%
rename from Discord.Net/ChannelTypes.cs
rename to src/Discord.Net/ChannelTypes.cs
diff --git a/src/Discord.Net/Discord.Net.xproj b/src/Discord.Net/Discord.Net.xproj
new file mode 100644
index 000000000..5518fc017
--- /dev/null
+++ b/src/Discord.Net/Discord.Net.xproj
@@ -0,0 +1,21 @@
+
+
+
+ 14.0
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+
+
+
+ acfb060b-ec8a-4926-b293-04c01e17ee23
+ Discord.Net
+ ..\..\artifacts\obj\$(MSBuildProjectName)
+ ..\..\artifacts\bin\$(MSBuildProjectName)\
+
+
+ 2.0
+
+
+ True
+
+
+
\ No newline at end of file
diff --git a/Discord.Net/DiscordClient.Events.cs b/src/Discord.Net/DiscordClient.Events.cs
similarity index 100%
rename from Discord.Net/DiscordClient.Events.cs
rename to src/Discord.Net/DiscordClient.Events.cs
diff --git a/Discord.Net/DiscordClient.cs b/src/Discord.Net/DiscordClient.cs
similarity index 93%
rename from Discord.Net/DiscordClient.cs
rename to src/Discord.Net/DiscordClient.cs
index 7c306390e..052fe47f7 100644
--- a/Discord.Net/DiscordClient.cs
+++ b/src/Discord.Net/DiscordClient.cs
@@ -18,7 +18,7 @@ namespace Discord
private DiscordWebSocket _webSocket;
private HttpOptions _httpOptions;
- private bool _isClosing, _isReady;
+ private bool _isReady;
public string UserId { get; private set; }
public User User => _users[UserId];
@@ -38,11 +38,14 @@ namespace Discord
public IEnumerable Roles => _roles;
private AsyncCache _roles;
+ private ManualResetEventSlim _isStopping;
+
public bool IsConnected => _isReady;
public DiscordClient()
{
- string version = typeof(DiscordClient).GetTypeInfo().Assembly.GetName().Version.ToString(2);
+ _isStopping = new ManualResetEventSlim(false);
+ string version = typeof(DiscordClient).GetTypeInfo().Assembly.GetName().Version.ToString(2);
_httpOptions = new HttpOptions($"Discord.Net/{version} (https://github.com/RogueException/Discord.Net)");
_servers = new AsyncCache(
@@ -152,12 +155,12 @@ namespace Discord
{
//Reconnect if we didn't cause the disconnect
RaiseDisconnected();
- while (!_isClosing)
+ while (!_isStopping.IsSet)
{
try
{
await Task.Delay(ReconnectDelay);
- await _webSocket.ConnectAsync(Endpoints.WebSocket_Hub, _httpOptions);
+ await _webSocket.ConnectAsync(Endpoints.WebSocket_Hub, true, _httpOptions);
break;
}
catch (Exception)
@@ -395,7 +398,7 @@ namespace Discord
public User FindUser(string name)
{
return _users
- .Where(x => string.Equals(x.Name, name, StringComparison.InvariantCultureIgnoreCase))
+ .Where(x => string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase))
.FirstOrDefault();
}
public User FindUser(string name, string discriminator)
@@ -405,7 +408,7 @@ namespace Discord
return _users
.Where(x =>
- string.Equals(x.Name, name, StringComparison.InvariantCultureIgnoreCase) &&
+ string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase) &&
x.Discriminator == discriminator
)
.FirstOrDefault();
@@ -418,7 +421,7 @@ namespace Discord
name = name.Substring(1);
return _users
- .Where(x => string.Equals(x.Name, name, StringComparison.InvariantCultureIgnoreCase))
+ .Where(x => string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase))
.FirstOrDefault();
}
@@ -426,7 +429,7 @@ namespace Discord
public Server FindServer(string name)
{
return _servers
- .Where(x => string.Equals(x.Name, name, StringComparison.InvariantCultureIgnoreCase))
+ .Where(x => string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase))
.FirstOrDefault();
}
@@ -437,7 +440,7 @@ namespace Discord
name = name.Substring(1);
return _channels
- .Where(x => string.Equals(x.Name, name, StringComparison.InvariantCultureIgnoreCase))
+ .Where(x => string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase))
.FirstOrDefault();
}
public Channel FindChannel(Server server, string name)
@@ -449,7 +452,7 @@ namespace Discord
return _channels
.Where(x =>
- string.Equals(x.Name, name, StringComparison.InvariantCultureIgnoreCase) &&
+ string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase) &&
x.ServerId == serverId
)
.FirstOrDefault();
@@ -461,7 +464,7 @@ namespace Discord
public Role FindRole(string serverId, string name)
{
return _roles
- .Where(x => string.Equals(x.Name, name, StringComparison.InvariantCultureIgnoreCase))
+ .Where(x => string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase))
.FirstOrDefault();
}
@@ -495,26 +498,39 @@ namespace Discord
//Auth
public async Task Connect(string email, string password)
{
- _isClosing = false;
+ _isStopping.Reset();
+
+ //Open websocket while we wait for login response
+ Task socketTask = _webSocket.ConnectAsync(Endpoints.WebSocket_Hub, false, _httpOptions);
var response = await DiscordAPI.Login(email, password, _httpOptions);
_httpOptions.Token = response.Token;
- await _webSocket.ConnectAsync(Endpoints.WebSocket_Hub, _httpOptions);
+
+ //Wait for websocket to finish connecting, then send token
+ await socketTask;
+ _webSocket.Login(_httpOptions);
+
_isReady = true;
}
public async Task ConnectAnonymous(string username)
{
- _isClosing = false;
+ _isStopping.Reset();
+
+ //Open websocket while we wait for login response
+ Task socketTask = _webSocket.ConnectAsync(Endpoints.WebSocket_Hub, false, _httpOptions);
var response = await DiscordAPI.LoginAnonymous(username, _httpOptions);
_httpOptions.Token = response.Token;
- await _webSocket.ConnectAsync(Endpoints.WebSocket_Hub, _httpOptions);
+
+ //Wait for websocket to finish connecting, then send token
+ await socketTask;
+ _webSocket.Login(_httpOptions);
+
_isReady = true;
}
public async Task Disconnect()
{
_isReady = false;
- _isClosing = true;
+ _isStopping.Set();
await _webSocket.DisconnectAsync();
- _isClosing = false;
_channels.Clear();
_messages.Clear();
@@ -783,12 +799,14 @@ namespace Discord
if (!_isReady)
throw new InvalidOperationException("The client is not currently connected to Discord");
}
+
+ ///
+ /// Blocking call that will not return until client has been stopped. This is mainly intended for use in console applications.
+ ///
+ ///
public void Block()
{
- //Blocking call for console apps
- //TODO: Improve this
- while (!_isClosing)
- Thread.Sleep(1000);
+ _isStopping.Wait();
}
}
}
diff --git a/Discord.Net/DiscordWebSocket.Events.cs b/src/Discord.Net/DiscordWebSocket.Events.cs
similarity index 100%
rename from Discord.Net/DiscordWebSocket.Events.cs
rename to src/Discord.Net/DiscordWebSocket.Events.cs
diff --git a/Discord.Net/DiscordWebSocket.cs b/src/Discord.Net/DiscordWebSocket.cs
similarity index 96%
rename from Discord.Net/DiscordWebSocket.cs
rename to src/Discord.Net/DiscordWebSocket.cs
index 27caee53d..ff0f8f555 100644
--- a/Discord.Net/DiscordWebSocket.cs
+++ b/src/Discord.Net/DiscordWebSocket.cs
@@ -25,7 +25,7 @@ namespace Discord
private DateTime _lastHeartbeat;
private AutoResetEvent _connectWaitOnLogin, _connectWaitOnLogin2;
- public async Task ConnectAsync(string url, HttpOptions options)
+ public async Task ConnectAsync(string url, bool autoLogin, HttpOptions options)
{
await DisconnectAsync();
@@ -34,7 +34,6 @@ namespace Discord
_sendQueue = new ConcurrentQueue();
_webSocket = new ClientWebSocket();
- _webSocket.Options.Cookies = options.Cookies;
_webSocket.Options.KeepAliveInterval = TimeSpan.Zero;
_cancelToken = new CancellationTokenSource();
@@ -58,6 +57,11 @@ namespace Discord
RaiseDisconnected();
});
+ if (autoLogin)
+ Login(options);
+ }
+ public void Login(HttpOptions options)
+ {
WebSocketCommands.Login msg = new WebSocketCommands.Login();
msg.Payload.Token = options.Token;
msg.Payload.Properties["$os"] = "";
@@ -65,12 +69,14 @@ namespace Discord
msg.Payload.Properties["$device"] = "Discord.Net";
msg.Payload.Properties["$referrer"] = "";
msg.Payload.Properties["$referring_domain"] = "";
- SendMessage(msg, cancelToken);
+ SendMessage(msg, _cancelToken.Token);
if (!_connectWaitOnLogin.WaitOne(ReadyTimeout)) //Pre-Event
throw new Exception("No reply from Discord server");
_connectWaitOnLogin2.WaitOne(); //Post-Event
- }
+
+ RaiseConnected();
+ }
public async Task DisconnectAsync()
{
if (_tasks != null)
@@ -82,8 +88,6 @@ namespace Discord
private async Task ReceiveAsync()
{
- RaiseConnected();
-
var cancelToken = _cancelToken.Token;
var buffer = new byte[ReceiveChunkSize];
var builder = new StringBuilder();
diff --git a/Discord.Net/Helpers/AsyncCache.cs b/src/Discord.Net/Helpers/AsyncCache.cs
similarity index 100%
rename from Discord.Net/Helpers/AsyncCache.cs
rename to src/Discord.Net/Helpers/AsyncCache.cs
diff --git a/Discord.Net/Helpers/Http.cs b/src/Discord.Net/Helpers/Http.cs
similarity index 86%
rename from Discord.Net/Helpers/Http.cs
rename to src/Discord.Net/Helpers/Http.cs
index b08e01777..efa240e97 100644
--- a/Discord.Net/Helpers/Http.cs
+++ b/src/Discord.Net/Helpers/Http.cs
@@ -3,7 +3,6 @@ using System;
using System.IO;
using System.IO.Compression;
using System.Net;
-using System.Net.Cache;
using System.Text;
using System.Threading.Tasks;
@@ -13,18 +12,15 @@ namespace Discord.Helpers
{
public readonly string UserAgent;
public string Token;
- public CookieContainer Cookies;
public HttpOptions(string userAgent)
{
UserAgent = userAgent;
- Cookies = new CookieContainer(1);
}
}
internal static class Http
{
- private static readonly RequestCachePolicy _cachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore);
#if DEBUG
private const bool _isDebug = true;
#else
@@ -107,12 +103,13 @@ namespace Discord.Helpers
//Create Request
HttpWebRequest request = WebRequest.CreateHttp(path);
request.Accept = "*/*";
+ request.Method = method;
+ request.Proxy = null;
request.Headers[HttpRequestHeader.AcceptLanguage] = "en-US;q=0.8";
request.Headers[HttpRequestHeader.AcceptEncoding] = "gzip, deflate";
- request.CachePolicy = _cachePolicy;
- request.CookieContainer = options.Cookies;
- request.Method = method;
- request.UserAgent = options.UserAgent;
+ request.Headers[HttpRequestHeader.UserAgent] = options.UserAgent;
+ request.Headers[HttpRequestHeader.Authorization] = options.Token;
+ //request.UserAgent = options.UserAgent;
//Add Payload
if (data != null)
@@ -140,18 +137,35 @@ namespace Discord.Helpers
largeBuffer.Write(smallBuffer, 0, bytesRead);
//Do we need to decompress?
- if (!string.IsNullOrEmpty(response.ContentEncoding))
+ string encoding = response.Headers[HttpResponseHeader.ContentEncoding];
+ if (!string.IsNullOrEmpty(encoding))
{
largeBuffer.Position = 0;
- using (var decoder = GetDecoder(response.ContentEncoding, largeBuffer))
+ using (var decoder = GetDecoder(encoding, largeBuffer))
using (var decodedStream = new MemoryStream())
{
decoder.CopyTo(decodedStream);
+#if !DOTNET
return Encoding.UTF8.GetString(decodedStream.GetBuffer(), 0, (int)decodedStream.Length);
+#else
+ ArraySegment buffer;
+ if (!decodedStream.TryGetBuffer(out buffer))
+ throw new InvalidOperationException("Failed to get response buffer.");
+ return Encoding.UTF8.GetString(buffer.Array, buffer.Offset, (int)decodedStream.Length);
+#endif
}
}
else
+ {
+#if !DOTNET
return Encoding.UTF8.GetString(largeBuffer.GetBuffer(), 0, (int)largeBuffer.Length);
+#else
+ ArraySegment buffer;
+ if (!largeBuffer.TryGetBuffer(out buffer))
+ throw new InvalidOperationException("Failed to get response buffer.");
+ return Encoding.UTF8.GetString(buffer.Array, buffer.Offset, (int)largeBuffer.Length);
+#endif
+ }
}
}
else
diff --git a/Discord.Net/Invite.cs b/src/Discord.Net/Invite.cs
similarity index 100%
rename from Discord.Net/Invite.cs
rename to src/Discord.Net/Invite.cs
diff --git a/Discord.Net/Membership.cs b/src/Discord.Net/Membership.cs
similarity index 100%
rename from Discord.Net/Membership.cs
rename to src/Discord.Net/Membership.cs
diff --git a/Discord.Net/Message.cs b/src/Discord.Net/Message.cs
similarity index 100%
rename from Discord.Net/Message.cs
rename to src/Discord.Net/Message.cs
diff --git a/Discord.Net/Regions.cs b/src/Discord.Net/Regions.cs
similarity index 100%
rename from Discord.Net/Regions.cs
rename to src/Discord.Net/Regions.cs
diff --git a/Discord.Net/Role.cs b/src/Discord.Net/Role.cs
similarity index 100%
rename from Discord.Net/Role.cs
rename to src/Discord.Net/Role.cs
diff --git a/Discord.Net/Server.cs b/src/Discord.Net/Server.cs
similarity index 100%
rename from Discord.Net/Server.cs
rename to src/Discord.Net/Server.cs
diff --git a/Discord.Net/User.cs b/src/Discord.Net/User.cs
similarity index 100%
rename from Discord.Net/User.cs
rename to src/Discord.Net/User.cs
diff --git a/src/Discord.Net/packages.config b/src/Discord.Net/packages.config
new file mode 100644
index 000000000..505e58836
--- /dev/null
+++ b/src/Discord.Net/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/Discord.Net/project.json b/src/Discord.Net/project.json
new file mode 100644
index 000000000..af79b0793
--- /dev/null
+++ b/src/Discord.Net/project.json
@@ -0,0 +1,28 @@
+{
+ "version": "0.3.3-*",
+ "description": "An unofficial .Net API wrapper for the Discord client.",
+ "authors": [ "RogueException" ],
+ "tags": [ "discord", "discordapp" ],
+ "projectUrl": "https://github.com/RogueException/Discord.Net",
+ "licenseUrl": "http://opensource.org/licenses/MIT",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/RogueException/Discord.Net"
+ },
+ "compilationOptions": {
+ "warningsAsErrors": true
+ },
+ "frameworks": {
+ "dotnet": {
+ "dependencies": {
+ "System.Collections.Concurrent": "4.0.10",
+ "System.IO.Compression": "4.0.0-beta-23109",
+ "System.Net.Requests": "4.0.10-beta-23109",
+ "System.Net.WebSockets.Client": "4.0.0-beta-23109",
+ "System.Runtime": "4.0.20",
+ "Microsoft.CSharp": "4.0.0",
+ "Newtonsoft.Json": "7.0.1"
+ }
+ }
+ }
+}
diff --git a/Discord.Net.Tests/Discord.Net.Tests.csproj b/test/Discord.Net.Tests/Discord.Net.Tests.csproj
similarity index 94%
rename from Discord.Net.Tests/Discord.Net.Tests.csproj
rename to test/Discord.Net.Tests/Discord.Net.Tests.csproj
index af0d9e395..27d5930b7 100644
--- a/Discord.Net.Tests/Discord.Net.Tests.csproj
+++ b/test/Discord.Net.Tests/Discord.Net.Tests.csproj
@@ -8,7 +8,7 @@
Properties
Discord.Net.Tests
Discord.Net.Tests
- v4.5.2
+ v4.6
512
{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
10.0
@@ -16,6 +16,7 @@
$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages
False
UnitTest
+
true
@@ -55,8 +56,8 @@
-
- {8d23f61b-723c-4966-859d-1119b28bcf19}
+
+ {8d71a857-879a-4a10-859e-5ff824ed6688}
Discord.Net
diff --git a/Discord.Net.Tests/Properties/AssemblyInfo.cs b/test/Discord.Net.Tests/Properties/AssemblyInfo.cs
similarity index 100%
rename from Discord.Net.Tests/Properties/AssemblyInfo.cs
rename to test/Discord.Net.Tests/Properties/AssemblyInfo.cs
diff --git a/Discord.Net.Tests/Tests.cs b/test/Discord.Net.Tests/Tests.cs
similarity index 100%
rename from Discord.Net.Tests/Tests.cs
rename to test/Discord.Net.Tests/Tests.cs