Merge branch 'concrete2' into dev
This commit is contained in:
@@ -3,7 +3,23 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
|||||||
# Visual Studio 14
|
# Visual Studio 14
|
||||||
VisualStudioVersion = 14.0.25420.1
|
VisualStudioVersion = 14.0.25420.1
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Discord.Net", "src\Discord.Net\Discord.Net.xproj", "{91E9E7BD-75C9-4E98-84AA-2C271922E5C2}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F7F3E124-93C7-4846-AE87-9CE12BD82859}"
|
||||||
|
ProjectSection(SolutionItems) = preProject
|
||||||
|
global.json = global.json
|
||||||
|
README.md = README.md
|
||||||
|
EndProjectSection
|
||||||
|
EndProject
|
||||||
|
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Discord.Net", "src\Discord.Net\Discord.Net.xproj", "{496DB20A-A455-4D01-B6BC-90FE6D7C6B81}"
|
||||||
|
EndProject
|
||||||
|
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Discord.Net.Core", "src\Discord.Net.Core\Discord.Net.Core.xproj", "{91E9E7BD-75C9-4E98-84AA-2C271922E5C2}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Impls", "Impls", "{288C363D-A636-4EAE-9AC1-4698B641B26E}"
|
||||||
|
EndProject
|
||||||
|
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Discord.Net.Rest", "src\Discord.Net.Rest\Discord.Net.Rest.xproj", "{BFC6DC28-0351-4573-926A-D4124244C04F}"
|
||||||
|
EndProject
|
||||||
|
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Discord.Net.WebSocket", "src\Discord.Net.WebSocket\Discord.Net.WebSocket.xproj", "{22AB6C66-536C-4AC2-BBDB-A8BC4EB6B14D}"
|
||||||
|
EndProject
|
||||||
|
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Discord.Net.Rpc", "src\Discord.Net.Rpc\Discord.Net.Rpc.xproj", "{5688A353-121E-40A1-8BFA-B17B91FB48FB}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Discord.Net.Commands", "src\Discord.Net.Commands\Discord.Net.Commands.xproj", "{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}"
|
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Discord.Net.Commands", "src\Discord.Net.Commands\Discord.Net.Commands.xproj", "{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}"
|
||||||
EndProject
|
EndProject
|
||||||
@@ -13,10 +29,26 @@ Global
|
|||||||
Release|Any CPU = Release|Any CPU
|
Release|Any CPU = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{496DB20A-A455-4D01-B6BC-90FE6D7C6B81}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{496DB20A-A455-4D01-B6BC-90FE6D7C6B81}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{496DB20A-A455-4D01-B6BC-90FE6D7C6B81}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{496DB20A-A455-4D01-B6BC-90FE6D7C6B81}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{91E9E7BD-75C9-4E98-84AA-2C271922E5C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{91E9E7BD-75C9-4E98-84AA-2C271922E5C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{91E9E7BD-75C9-4E98-84AA-2C271922E5C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{91E9E7BD-75C9-4E98-84AA-2C271922E5C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{91E9E7BD-75C9-4E98-84AA-2C271922E5C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{91E9E7BD-75C9-4E98-84AA-2C271922E5C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{91E9E7BD-75C9-4E98-84AA-2C271922E5C2}.Release|Any CPU.Build.0 = Release|Any CPU
|
{91E9E7BD-75C9-4E98-84AA-2C271922E5C2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{BFC6DC28-0351-4573-926A-D4124244C04F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{BFC6DC28-0351-4573-926A-D4124244C04F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{BFC6DC28-0351-4573-926A-D4124244C04F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{BFC6DC28-0351-4573-926A-D4124244C04F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{22AB6C66-536C-4AC2-BBDB-A8BC4EB6B14D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{22AB6C66-536C-4AC2-BBDB-A8BC4EB6B14D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{22AB6C66-536C-4AC2-BBDB-A8BC4EB6B14D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{22AB6C66-536C-4AC2-BBDB-A8BC4EB6B14D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{5688A353-121E-40A1-8BFA-B17B91FB48FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{5688A353-121E-40A1-8BFA-B17B91FB48FB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{5688A353-121E-40A1-8BFA-B17B91FB48FB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{5688A353-121E-40A1-8BFA-B17B91FB48FB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
@@ -25,4 +57,9 @@ Global
|
|||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
|
GlobalSection(NestedProjects) = preSolution
|
||||||
|
{BFC6DC28-0351-4573-926A-D4124244C04F} = {288C363D-A636-4EAE-9AC1-4698B641B26E}
|
||||||
|
{22AB6C66-536C-4AC2-BBDB-A8BC4EB6B14D} = {288C363D-A636-4EAE-9AC1-4698B641B26E}
|
||||||
|
{5688A353-121E-40A1-8BFA-B17B91FB48FB} = {288C363D-A636-4EAE-9AC1-4698B641B26E}
|
||||||
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|||||||
3
src/Discord.Net.Commands/AssemblyInfo.cs
Normal file
3
src/Discord.Net.Commands/AssemblyInfo.cs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
[assembly: InternalsVisibleTo("Discord.Net.Tests")]
|
||||||
@@ -6,6 +6,7 @@ namespace Discord.Commands
|
|||||||
public class CommandAttribute : Attribute
|
public class CommandAttribute : Attribute
|
||||||
{
|
{
|
||||||
public string Text { get; }
|
public string Text { get; }
|
||||||
|
public RunMode RunMode { get; set; } = RunMode.Sync;
|
||||||
|
|
||||||
public CommandAttribute()
|
public CommandAttribute()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Discord.Commands
|
||||||
|
{
|
||||||
|
[AttributeUsage(AttributeTargets.Class)]
|
||||||
|
public class DontAutoLoadAttribute : Attribute
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Discord.Commands
|
|
||||||
{
|
|
||||||
[AttributeUsage(AttributeTargets.Class)]
|
|
||||||
public class ModuleAttribute : Attribute
|
|
||||||
{
|
|
||||||
public string Prefix { get; }
|
|
||||||
public bool AutoLoad { get; set; }
|
|
||||||
|
|
||||||
public ModuleAttribute()
|
|
||||||
{
|
|
||||||
Prefix = null;
|
|
||||||
AutoLoad = true;
|
|
||||||
}
|
|
||||||
public ModuleAttribute(string prefix)
|
|
||||||
{
|
|
||||||
Prefix = prefix;
|
|
||||||
AutoLoad = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,6 +6,6 @@ namespace Discord.Commands
|
|||||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
|
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
|
||||||
public abstract class PreconditionAttribute : Attribute
|
public abstract class PreconditionAttribute : Attribute
|
||||||
{
|
{
|
||||||
public abstract Task<PreconditionResult> CheckPermissions(IUserMessage context, Command executingCommand, object moduleInstance);
|
public abstract Task<PreconditionResult> CheckPermissions(CommandContext context, CommandInfo command, IDependencyMap map);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ namespace Discord.Commands
|
|||||||
Contexts = contexts;
|
Contexts = contexts;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task<PreconditionResult> CheckPermissions(IUserMessage context, Command executingCommand, object moduleInstance)
|
public override Task<PreconditionResult> CheckPermissions(CommandContext context, CommandInfo command, IDependencyMap map)
|
||||||
{
|
{
|
||||||
bool isValid = false;
|
bool isValid = false;
|
||||||
|
|
||||||
|
|||||||
@@ -20,9 +20,9 @@ namespace Discord.Commands
|
|||||||
GuildPermission = null;
|
GuildPermission = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task<PreconditionResult> CheckPermissions(IUserMessage context, Command executingCommand, object moduleInstance)
|
public override Task<PreconditionResult> CheckPermissions(CommandContext context, CommandInfo command, IDependencyMap map)
|
||||||
{
|
{
|
||||||
var guildUser = context.Author as IGuildUser;
|
var guildUser = context.User as IGuildUser;
|
||||||
|
|
||||||
if (GuildPermission.HasValue)
|
if (GuildPermission.HasValue)
|
||||||
{
|
{
|
||||||
|
|||||||
18
src/Discord.Net.Commands/CommandContext.cs
Normal file
18
src/Discord.Net.Commands/CommandContext.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
namespace Discord.Commands
|
||||||
|
{
|
||||||
|
public struct CommandContext
|
||||||
|
{
|
||||||
|
public IGuild Guild { get; }
|
||||||
|
public IMessageChannel Channel { get; }
|
||||||
|
public IUser User { get; }
|
||||||
|
public IUserMessage Message { get; }
|
||||||
|
|
||||||
|
public CommandContext(IGuild guild, IMessageChannel channel, IUser user, IUserMessage msg)
|
||||||
|
{
|
||||||
|
Guild = guild;
|
||||||
|
Channel = channel;
|
||||||
|
User = user;
|
||||||
|
Message = msg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,38 +10,38 @@ using System.Threading.Tasks;
|
|||||||
namespace Discord.Commands
|
namespace Discord.Commands
|
||||||
{
|
{
|
||||||
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
|
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
|
||||||
public class Command
|
public class CommandInfo
|
||||||
{
|
{
|
||||||
private static readonly MethodInfo _convertParamsMethod = typeof(Command).GetTypeInfo().GetDeclaredMethod(nameof(ConvertParamsList));
|
private static readonly MethodInfo _convertParamsMethod = typeof(CommandInfo).GetTypeInfo().GetDeclaredMethod(nameof(ConvertParamsList));
|
||||||
private static readonly ConcurrentDictionary<Type, Func<IEnumerable<object>, object>> _arrayConverters = new ConcurrentDictionary<Type, Func<IEnumerable<object>, object>>();
|
private static readonly ConcurrentDictionary<Type, Func<IEnumerable<object>, object>> _arrayConverters = new ConcurrentDictionary<Type, Func<IEnumerable<object>, object>>();
|
||||||
|
|
||||||
private readonly object _instance;
|
private readonly Func<CommandContext, object[], Task> _action;
|
||||||
private readonly Func<IUserMessage, IReadOnlyList<object>, Task> _action;
|
|
||||||
|
|
||||||
public MethodInfo Source { get; }
|
public MethodInfo Source { get; }
|
||||||
public Module Module { get; }
|
public ModuleInfo Module { get; }
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
public string Summary { get; }
|
public string Summary { get; }
|
||||||
public string Remarks { get; }
|
public string Remarks { get; }
|
||||||
public string Text { get; }
|
public string Text { get; }
|
||||||
public int Priority { get; }
|
public int Priority { get; }
|
||||||
public bool HasVarArgs { get; }
|
public bool HasVarArgs { get; }
|
||||||
|
public RunMode RunMode { get; }
|
||||||
public IReadOnlyList<string> Aliases { get; }
|
public IReadOnlyList<string> Aliases { get; }
|
||||||
public IReadOnlyList<CommandParameter> Parameters { get; }
|
public IReadOnlyList<CommandParameter> Parameters { get; }
|
||||||
public IReadOnlyList<PreconditionAttribute> Preconditions { get; }
|
public IReadOnlyList<PreconditionAttribute> Preconditions { get; }
|
||||||
|
|
||||||
internal Command(MethodInfo source, Module module, object instance, CommandAttribute attribute, string groupPrefix)
|
internal CommandInfo(MethodInfo source, ModuleInfo module, CommandAttribute attribute, string groupPrefix)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Source = source;
|
Source = source;
|
||||||
Module = module;
|
Module = module;
|
||||||
_instance = instance;
|
|
||||||
|
|
||||||
Name = source.Name;
|
Name = source.Name;
|
||||||
|
|
||||||
if (attribute.Text == null)
|
if (attribute.Text == null)
|
||||||
Text = groupPrefix;
|
Text = groupPrefix;
|
||||||
|
RunMode = attribute.RunMode;
|
||||||
|
|
||||||
if (groupPrefix != "")
|
if (groupPrefix != "")
|
||||||
groupPrefix += " ";
|
groupPrefix += " ";
|
||||||
@@ -85,18 +85,18 @@ namespace Discord.Commands
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<PreconditionResult> CheckPreconditions(IUserMessage context)
|
public async Task<PreconditionResult> CheckPreconditions(CommandContext context, IDependencyMap map = null)
|
||||||
{
|
{
|
||||||
foreach (PreconditionAttribute precondition in Module.Preconditions)
|
foreach (PreconditionAttribute precondition in Module.Preconditions)
|
||||||
{
|
{
|
||||||
var result = await precondition.CheckPermissions(context, this, Module.Instance).ConfigureAwait(false);
|
var result = await precondition.CheckPermissions(context, this, map).ConfigureAwait(false);
|
||||||
if (!result.IsSuccess)
|
if (!result.IsSuccess)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (PreconditionAttribute precondition in Preconditions)
|
foreach (PreconditionAttribute precondition in Preconditions)
|
||||||
{
|
{
|
||||||
var result = await precondition.CheckPermissions(context, this, Module.Instance).ConfigureAwait(false);
|
var result = await precondition.CheckPermissions(context, this, map).ConfigureAwait(false);
|
||||||
if (!result.IsSuccess)
|
if (!result.IsSuccess)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -104,7 +104,7 @@ namespace Discord.Commands
|
|||||||
return PreconditionResult.FromSuccess();
|
return PreconditionResult.FromSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ParseResult> Parse(IUserMessage context, SearchResult searchResult, PreconditionResult? preconditionResult = null)
|
public async Task<ParseResult> Parse(CommandContext context, SearchResult searchResult, PreconditionResult? preconditionResult = null)
|
||||||
{
|
{
|
||||||
if (!searchResult.IsSuccess)
|
if (!searchResult.IsSuccess)
|
||||||
return ParseResult.FromError(searchResult);
|
return ParseResult.FromError(searchResult);
|
||||||
@@ -125,7 +125,7 @@ namespace Discord.Commands
|
|||||||
|
|
||||||
return await CommandParser.ParseArgs(this, context, input, 0).ConfigureAwait(false);
|
return await CommandParser.ParseArgs(this, context, input, 0).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
public Task<ExecuteResult> Execute(IUserMessage context, ParseResult parseResult)
|
public Task<ExecuteResult> Execute(CommandContext context, ParseResult parseResult)
|
||||||
{
|
{
|
||||||
if (!parseResult.IsSuccess)
|
if (!parseResult.IsSuccess)
|
||||||
return Task.FromResult(ExecuteResult.FromError(parseResult));
|
return Task.FromResult(ExecuteResult.FromError(parseResult));
|
||||||
@@ -148,11 +148,23 @@ namespace Discord.Commands
|
|||||||
|
|
||||||
return Execute(context, argList, paramList);
|
return Execute(context, argList, paramList);
|
||||||
}
|
}
|
||||||
public async Task<ExecuteResult> Execute(IUserMessage context, IEnumerable<object> argList, IEnumerable<object> paramList)
|
public async Task<ExecuteResult> Execute(CommandContext context, IEnumerable<object> argList, IEnumerable<object> paramList)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _action.Invoke(context, GenerateArgs(argList, paramList)).ConfigureAwait(false);//Note: This code may need context
|
var args = GenerateArgs(argList, paramList);
|
||||||
|
switch (RunMode)
|
||||||
|
{
|
||||||
|
case RunMode.Sync: //Always sync
|
||||||
|
await _action(context, args).ConfigureAwait(false);
|
||||||
|
break;
|
||||||
|
case RunMode.Mixed: //Sync until first await statement
|
||||||
|
var t1 = _action(context, args);
|
||||||
|
break;
|
||||||
|
case RunMode.Async: //Always async
|
||||||
|
var t2 = Task.Run(() => _action(context, args));
|
||||||
|
break;
|
||||||
|
}
|
||||||
return ExecuteResult.FromSuccess();
|
return ExecuteResult.FromSuccess();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -169,11 +181,9 @@ namespace Discord.Commands
|
|||||||
private IReadOnlyList<CommandParameter> BuildParameters(MethodInfo methodInfo)
|
private IReadOnlyList<CommandParameter> BuildParameters(MethodInfo methodInfo)
|
||||||
{
|
{
|
||||||
var parameters = methodInfo.GetParameters();
|
var parameters = methodInfo.GetParameters();
|
||||||
if (parameters.Length == 0 || parameters[0].ParameterType != typeof(IUserMessage))
|
|
||||||
throw new InvalidOperationException($"The first parameter of a command must be {nameof(IUserMessage)}.");
|
|
||||||
|
|
||||||
var paramBuilder = ImmutableArray.CreateBuilder<CommandParameter>(parameters.Length - 1);
|
var paramBuilder = ImmutableArray.CreateBuilder<CommandParameter>(parameters.Length);
|
||||||
for (int i = 1; i < parameters.Length; i++)
|
for (int i = 0; i < parameters.Length; i++)
|
||||||
{
|
{
|
||||||
var parameter = parameters[i];
|
var parameter = parameters[i];
|
||||||
var type = parameter.ParameterType;
|
var type = parameter.ParameterType;
|
||||||
@@ -209,19 +219,23 @@ namespace Discord.Commands
|
|||||||
}
|
}
|
||||||
return paramBuilder.ToImmutable();
|
return paramBuilder.ToImmutable();
|
||||||
}
|
}
|
||||||
private Func<IUserMessage, IReadOnlyList<object>, Task> BuildAction(MethodInfo methodInfo)
|
private Func<CommandContext, object[], Task> BuildAction(MethodInfo methodInfo)
|
||||||
{
|
{
|
||||||
if (methodInfo.ReturnType != typeof(Task))
|
if (methodInfo.ReturnType != typeof(Task))
|
||||||
throw new InvalidOperationException("Commands must return a non-generic Task.");
|
throw new InvalidOperationException("Commands must return a non-generic Task.");
|
||||||
|
|
||||||
return (msg, args) =>
|
return (context, args) =>
|
||||||
{
|
{
|
||||||
object[] newArgs = new object[args.Count + 1];
|
var instance = Module.CreateInstance();
|
||||||
newArgs[0] = msg;
|
instance.Context = context;
|
||||||
for (int i = 0; i < args.Count; i++)
|
try
|
||||||
newArgs[i + 1] = args[i];
|
{
|
||||||
var result = methodInfo.Invoke(_instance, newArgs);
|
return methodInfo.Invoke(instance, args) as Task ?? Task.CompletedTask;
|
||||||
return result as Task ?? Task.CompletedTask;
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
(instance as IDisposable)?.Dispose();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ namespace Discord.Commands
|
|||||||
DefaultValue = defaultValue;
|
DefaultValue = defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<TypeReaderResult> Parse(IUserMessage context, string input)
|
public async Task<TypeReaderResult> Parse(CommandContext context, string input)
|
||||||
{
|
{
|
||||||
return await _reader.Read(context, input).ConfigureAwait(false);
|
return await _reader.Read(context, input).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ namespace Discord.Commands
|
|||||||
QuotedParameter
|
QuotedParameter
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<ParseResult> ParseArgs(Command command, IUserMessage context, string input, int startPos)
|
public static async Task<ParseResult> ParseArgs(CommandInfo command, CommandContext context, string input, int startPos)
|
||||||
{
|
{
|
||||||
CommandParameter curParam = null;
|
CommandParameter curParam = null;
|
||||||
StringBuilder argBuilder = new StringBuilder(input.Length);
|
StringBuilder argBuilder = new StringBuilder(input.Length);
|
||||||
|
|||||||
@@ -11,21 +11,25 @@ namespace Discord.Commands
|
|||||||
{
|
{
|
||||||
public class CommandService
|
public class CommandService
|
||||||
{
|
{
|
||||||
|
private static readonly TypeInfo _moduleTypeInfo = typeof(ModuleBase).GetTypeInfo();
|
||||||
|
|
||||||
private readonly SemaphoreSlim _moduleLock;
|
private readonly SemaphoreSlim _moduleLock;
|
||||||
private readonly ConcurrentDictionary<Type, Module> _modules;
|
private readonly ConcurrentDictionary<Type, ModuleInfo> _moduleDefs;
|
||||||
private readonly ConcurrentDictionary<Type, TypeReader> _typeReaders;
|
private readonly ConcurrentDictionary<Type, TypeReader> _typeReaders;
|
||||||
private readonly CommandMap _map;
|
private readonly CommandMap _map;
|
||||||
|
|
||||||
public IEnumerable<Module> Modules => _modules.Select(x => x.Value);
|
public IEnumerable<ModuleInfo> Modules => _moduleDefs.Select(x => x.Value);
|
||||||
public IEnumerable<Command> Commands => _modules.SelectMany(x => x.Value.Commands);
|
public IEnumerable<CommandInfo> Commands => _moduleDefs.SelectMany(x => x.Value.Commands);
|
||||||
|
|
||||||
public CommandService()
|
public CommandService()
|
||||||
{
|
{
|
||||||
_moduleLock = new SemaphoreSlim(1, 1);
|
_moduleLock = new SemaphoreSlim(1, 1);
|
||||||
_modules = new ConcurrentDictionary<Type, Module>();
|
_moduleDefs = new ConcurrentDictionary<Type, ModuleInfo>();
|
||||||
_map = new CommandMap();
|
_map = new CommandMap();
|
||||||
_typeReaders = new ConcurrentDictionary<Type, TypeReader>
|
_typeReaders = new ConcurrentDictionary<Type, TypeReader>
|
||||||
{
|
{
|
||||||
|
[typeof(bool)] = new SimpleTypeReader<bool>(),
|
||||||
|
[typeof(char)] = new SimpleTypeReader<char>(),
|
||||||
[typeof(string)] = new SimpleTypeReader<string>(),
|
[typeof(string)] = new SimpleTypeReader<string>(),
|
||||||
[typeof(byte)] = new SimpleTypeReader<byte>(),
|
[typeof(byte)] = new SimpleTypeReader<byte>(),
|
||||||
[typeof(sbyte)] = new SimpleTypeReader<sbyte>(),
|
[typeof(sbyte)] = new SimpleTypeReader<sbyte>(),
|
||||||
@@ -43,7 +47,6 @@ namespace Discord.Commands
|
|||||||
|
|
||||||
[typeof(IMessage)] = new MessageTypeReader<IMessage>(),
|
[typeof(IMessage)] = new MessageTypeReader<IMessage>(),
|
||||||
[typeof(IUserMessage)] = new MessageTypeReader<IUserMessage>(),
|
[typeof(IUserMessage)] = new MessageTypeReader<IUserMessage>(),
|
||||||
//[typeof(ISystemMessage)] = new MessageTypeReader<ISystemMessage>(),
|
|
||||||
[typeof(IChannel)] = new ChannelTypeReader<IChannel>(),
|
[typeof(IChannel)] = new ChannelTypeReader<IChannel>(),
|
||||||
[typeof(IDMChannel)] = new ChannelTypeReader<IDMChannel>(),
|
[typeof(IDMChannel)] = new ChannelTypeReader<IDMChannel>(),
|
||||||
[typeof(IGroupChannel)] = new ChannelTypeReader<IGroupChannel>(),
|
[typeof(IGroupChannel)] = new ChannelTypeReader<IGroupChannel>(),
|
||||||
@@ -53,19 +56,109 @@ namespace Discord.Commands
|
|||||||
[typeof(ITextChannel)] = new ChannelTypeReader<ITextChannel>(),
|
[typeof(ITextChannel)] = new ChannelTypeReader<ITextChannel>(),
|
||||||
[typeof(IVoiceChannel)] = new ChannelTypeReader<IVoiceChannel>(),
|
[typeof(IVoiceChannel)] = new ChannelTypeReader<IVoiceChannel>(),
|
||||||
|
|
||||||
//[typeof(IGuild)] = new GuildTypeReader<IGuild>(),
|
|
||||||
|
|
||||||
[typeof(IRole)] = new RoleTypeReader<IRole>(),
|
[typeof(IRole)] = new RoleTypeReader<IRole>(),
|
||||||
|
|
||||||
//[typeof(IInvite)] = new InviteTypeReader<IInvite>(),
|
|
||||||
//[typeof(IInviteMetadata)] = new InviteTypeReader<IInviteMetadata>(),
|
|
||||||
|
|
||||||
[typeof(IUser)] = new UserTypeReader<IUser>(),
|
[typeof(IUser)] = new UserTypeReader<IUser>(),
|
||||||
[typeof(IGroupUser)] = new UserTypeReader<IGroupUser>(),
|
[typeof(IGroupUser)] = new UserTypeReader<IGroupUser>(),
|
||||||
[typeof(IGuildUser)] = new UserTypeReader<IGuildUser>(),
|
[typeof(IGuildUser)] = new UserTypeReader<IGuildUser>(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Modules
|
||||||
|
public async Task<ModuleInfo> AddModule<T>(IDependencyMap dependencyMap = null)
|
||||||
|
{
|
||||||
|
await _moduleLock.WaitAsync().ConfigureAwait(false);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_moduleDefs.ContainsKey(typeof(T)))
|
||||||
|
throw new ArgumentException($"This module has already been added.");
|
||||||
|
|
||||||
|
var typeInfo = typeof(T).GetTypeInfo();
|
||||||
|
if (!_moduleTypeInfo.IsAssignableFrom(typeInfo))
|
||||||
|
throw new ArgumentException($"Modules must inherit ModuleBase.");
|
||||||
|
|
||||||
|
return AddModuleInternal(typeInfo, dependencyMap);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_moduleLock.Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public async Task<IEnumerable<ModuleInfo>> AddModules(Assembly assembly, IDependencyMap dependencyMap = null)
|
||||||
|
{
|
||||||
|
var moduleDefs = ImmutableArray.CreateBuilder<ModuleInfo>();
|
||||||
|
await _moduleLock.WaitAsync().ConfigureAwait(false);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
foreach (var type in assembly.ExportedTypes)
|
||||||
|
{
|
||||||
|
if (!_moduleDefs.ContainsKey(type))
|
||||||
|
{
|
||||||
|
var typeInfo = type.GetTypeInfo();
|
||||||
|
if (_moduleTypeInfo.IsAssignableFrom(typeInfo))
|
||||||
|
{
|
||||||
|
var dontAutoLoad = typeInfo.GetCustomAttribute<DontAutoLoadAttribute>();
|
||||||
|
if (dontAutoLoad == null)
|
||||||
|
moduleDefs.Add(AddModuleInternal(typeInfo, dependencyMap));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return moduleDefs.ToImmutable();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_moduleLock.Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private ModuleInfo AddModuleInternal(TypeInfo typeInfo, IDependencyMap dependencyMap)
|
||||||
|
{
|
||||||
|
var moduleDef = new ModuleInfo(typeInfo, this, dependencyMap);
|
||||||
|
_moduleDefs[typeInfo.BaseType] = moduleDef;
|
||||||
|
|
||||||
|
foreach (var cmd in moduleDef.Commands)
|
||||||
|
_map.AddCommand(cmd);
|
||||||
|
|
||||||
|
return moduleDef;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> RemoveModule(ModuleInfo module)
|
||||||
|
{
|
||||||
|
await _moduleLock.WaitAsync().ConfigureAwait(false);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return RemoveModuleInternal(module.Source.BaseType);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_moduleLock.Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public async Task<bool> RemoveModule<T>()
|
||||||
|
{
|
||||||
|
await _moduleLock.WaitAsync().ConfigureAwait(false);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return RemoveModuleInternal(typeof(T));
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_moduleLock.Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private bool RemoveModuleInternal(Type type)
|
||||||
|
{
|
||||||
|
ModuleInfo unloadedModule;
|
||||||
|
if (_moduleDefs.TryRemove(type, out unloadedModule))
|
||||||
|
{
|
||||||
|
foreach (var cmd in unloadedModule.Commands)
|
||||||
|
_map.RemoveCommand(cmd);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Type Readers
|
||||||
public void AddTypeReader<T>(TypeReader reader)
|
public void AddTypeReader<T>(TypeReader reader)
|
||||||
{
|
{
|
||||||
_typeReaders[typeof(T)] = reader;
|
_typeReaders[typeof(T)] = reader;
|
||||||
@@ -82,102 +175,9 @@ namespace Discord.Commands
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Module> Load(object moduleInstance)
|
//Execution
|
||||||
{
|
public SearchResult Search(CommandContext context, int argPos) => Search(context, context.Message.Content.Substring(argPos));
|
||||||
await _moduleLock.WaitAsync().ConfigureAwait(false);
|
public SearchResult Search(CommandContext context, string input)
|
||||||
try
|
|
||||||
{
|
|
||||||
if (_modules.ContainsKey(moduleInstance.GetType()))
|
|
||||||
throw new ArgumentException($"This module has already been loaded.");
|
|
||||||
|
|
||||||
var typeInfo = moduleInstance.GetType().GetTypeInfo();
|
|
||||||
var moduleAttr = typeInfo.GetCustomAttribute<ModuleAttribute>();
|
|
||||||
if (moduleAttr == null)
|
|
||||||
throw new ArgumentException($"Modules must be marked with ModuleAttribute.");
|
|
||||||
|
|
||||||
return LoadInternal(moduleInstance, moduleAttr, typeInfo, null);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
_moduleLock.Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private Module LoadInternal(object moduleInstance, ModuleAttribute moduleAttr, TypeInfo typeInfo, IDependencyMap dependencyMap)
|
|
||||||
{
|
|
||||||
if (_modules.ContainsKey(moduleInstance.GetType()))
|
|
||||||
return _modules[moduleInstance.GetType()];
|
|
||||||
|
|
||||||
var loadedModule = new Module(typeInfo, this, moduleInstance, moduleAttr, dependencyMap);
|
|
||||||
_modules[moduleInstance.GetType()] = loadedModule;
|
|
||||||
|
|
||||||
foreach (var cmd in loadedModule.Commands)
|
|
||||||
_map.AddCommand(cmd);
|
|
||||||
|
|
||||||
return loadedModule;
|
|
||||||
}
|
|
||||||
public async Task<IEnumerable<Module>> LoadAssembly(Assembly assembly, IDependencyMap dependencyMap = null)
|
|
||||||
{
|
|
||||||
var modules = ImmutableArray.CreateBuilder<Module>();
|
|
||||||
await _moduleLock.WaitAsync().ConfigureAwait(false);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
foreach (var type in assembly.ExportedTypes)
|
|
||||||
{
|
|
||||||
var typeInfo = type.GetTypeInfo();
|
|
||||||
var moduleAttr = typeInfo.GetCustomAttribute<ModuleAttribute>();
|
|
||||||
if (moduleAttr != null && moduleAttr.AutoLoad)
|
|
||||||
{
|
|
||||||
var moduleInstance = ReflectionUtils.CreateObject(typeInfo, this, dependencyMap);
|
|
||||||
modules.Add(LoadInternal(moduleInstance, moduleAttr, typeInfo, dependencyMap));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return modules.ToImmutable();
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
_moduleLock.Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<bool> Unload(Module module)
|
|
||||||
{
|
|
||||||
await _moduleLock.WaitAsync().ConfigureAwait(false);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return UnloadInternal(module.Instance);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
_moduleLock.Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public async Task<bool> Unload(object moduleInstance)
|
|
||||||
{
|
|
||||||
await _moduleLock.WaitAsync().ConfigureAwait(false);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return UnloadInternal(moduleInstance);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
_moduleLock.Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private bool UnloadInternal(object module)
|
|
||||||
{
|
|
||||||
Module unloadedModule;
|
|
||||||
if (_modules.TryRemove(module.GetType(), out unloadedModule))
|
|
||||||
{
|
|
||||||
foreach (var cmd in unloadedModule.Commands)
|
|
||||||
_map.RemoveCommand(cmd);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SearchResult Search(IUserMessage message, int argPos) => Search(message, message.Content.Substring(argPos));
|
|
||||||
public SearchResult Search(IUserMessage message, string input)
|
|
||||||
{
|
{
|
||||||
string lowerInput = input.ToLowerInvariant();
|
string lowerInput = input.ToLowerInvariant();
|
||||||
var matches = _map.GetCommands(input).OrderByDescending(x => x.Priority).ToImmutableArray();
|
var matches = _map.GetCommands(input).OrderByDescending(x => x.Priority).ToImmutableArray();
|
||||||
@@ -188,18 +188,18 @@ namespace Discord.Commands
|
|||||||
return SearchResult.FromError(CommandError.UnknownCommand, "Unknown command.");
|
return SearchResult.FromError(CommandError.UnknownCommand, "Unknown command.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<IResult> Execute(IUserMessage message, int argPos, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
|
public Task<IResult> Execute(CommandContext context, int argPos, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
|
||||||
=> Execute(message, message.Content.Substring(argPos), multiMatchHandling);
|
=> Execute(context, context.Message.Content.Substring(argPos), multiMatchHandling);
|
||||||
public async Task<IResult> Execute(IUserMessage message, string input, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
|
public async Task<IResult> Execute(CommandContext context, string input, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
|
||||||
{
|
{
|
||||||
var searchResult = Search(message, input);
|
var searchResult = Search(context, input);
|
||||||
if (!searchResult.IsSuccess)
|
if (!searchResult.IsSuccess)
|
||||||
return searchResult;
|
return searchResult;
|
||||||
|
|
||||||
var commands = searchResult.Commands;
|
var commands = searchResult.Commands;
|
||||||
for (int i = commands.Count - 1; i >= 0; i--)
|
for (int i = commands.Count - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
var preconditionResult = await commands[i].CheckPreconditions(message);
|
var preconditionResult = await commands[i].CheckPreconditions(context).ConfigureAwait(false);
|
||||||
if (!preconditionResult.IsSuccess)
|
if (!preconditionResult.IsSuccess)
|
||||||
{
|
{
|
||||||
if (commands.Count == 1)
|
if (commands.Count == 1)
|
||||||
@@ -208,17 +208,17 @@ namespace Discord.Commands
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var parseResult = await commands[i].Parse(message, searchResult, preconditionResult);
|
var parseResult = await commands[i].Parse(context, searchResult, preconditionResult).ConfigureAwait(false);
|
||||||
if (!parseResult.IsSuccess)
|
if (!parseResult.IsSuccess)
|
||||||
{
|
{
|
||||||
if (parseResult.Error == CommandError.MultipleMatches)
|
if (parseResult.Error == CommandError.MultipleMatches)
|
||||||
{
|
{
|
||||||
TypeReaderValue[] argList, paramList;
|
IReadOnlyList<TypeReaderValue> argList, paramList;
|
||||||
switch (multiMatchHandling)
|
switch (multiMatchHandling)
|
||||||
{
|
{
|
||||||
case MultiMatchHandling.Best:
|
case MultiMatchHandling.Best:
|
||||||
argList = parseResult.ArgValues.Select(x => x.Values.OrderByDescending(y => y.Score).First()).ToArray();
|
argList = parseResult.ArgValues.Select(x => x.Values.OrderByDescending(y => y.Score).First()).ToImmutableArray();
|
||||||
paramList = parseResult.ParamValues.Select(x => x.Values.OrderByDescending(y => y.Score).First()).ToArray();
|
paramList = parseResult.ParamValues.Select(x => x.Values.OrderByDescending(y => y.Score).First()).ToImmutableArray();
|
||||||
parseResult = ParseResult.FromSuccess(argList, paramList);
|
parseResult = ParseResult.FromSuccess(argList, paramList);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -233,7 +233,7 @@ namespace Discord.Commands
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return await commands[i].Execute(message, parseResult);
|
return await commands[i].Execute(context, parseResult).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return SearchResult.FromError(CommandError.UnknownCommand, "This input does not match any overload.");
|
return SearchResult.FromError(CommandError.UnknownCommand, "This input does not match any overload.");
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
if (text.Length < endPos + 2 || text[endPos + 1] != ' ') return false; //Must end in "> "
|
if (text.Length < endPos + 2 || text[endPos + 1] != ' ') return false; //Must end in "> "
|
||||||
|
|
||||||
ulong userId;
|
ulong userId;
|
||||||
if (!MentionUtils.TryParseUser(text.Substring(0, endPos + 2), out userId)) return false;
|
if (!MentionUtils.TryParseUser(text.Substring(0, endPos + 1), out userId)) return false;
|
||||||
if (userId == user.Id)
|
if (userId == user.Id)
|
||||||
{
|
{
|
||||||
argPos = endPos + 2;
|
argPos = endPos + 2;
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ namespace Discord.Commands
|
|||||||
_nodes = new ConcurrentDictionary<string, CommandMapNode>();
|
_nodes = new ConcurrentDictionary<string, CommandMapNode>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddCommand(Command command)
|
public void AddCommand(CommandInfo command)
|
||||||
{
|
{
|
||||||
foreach (string text in command.Aliases)
|
foreach (string text in command.Aliases)
|
||||||
{
|
{
|
||||||
@@ -35,7 +35,7 @@ namespace Discord.Commands
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public void RemoveCommand(Command command)
|
public void RemoveCommand(CommandInfo command)
|
||||||
{
|
{
|
||||||
foreach (string text in command.Aliases)
|
foreach (string text in command.Aliases)
|
||||||
{
|
{
|
||||||
@@ -60,7 +60,7 @@ namespace Discord.Commands
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<Command> GetCommands(string text)
|
public IEnumerable<CommandInfo> GetCommands(string text)
|
||||||
{
|
{
|
||||||
int nextSpace = NextWhitespace(text);
|
int nextSpace = NextWhitespace(text);
|
||||||
string name;
|
string name;
|
||||||
@@ -76,7 +76,7 @@ namespace Discord.Commands
|
|||||||
if (_nodes.TryGetValue(name, out nextNode))
|
if (_nodes.TryGetValue(name, out nextNode))
|
||||||
return nextNode.GetCommands(text, nextSpace + 1);
|
return nextNode.GetCommands(text, nextSpace + 1);
|
||||||
else
|
else
|
||||||
return Enumerable.Empty<Command>();
|
return Enumerable.Empty<CommandInfo>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace Discord.Commands
|
|||||||
private readonly ConcurrentDictionary<string, CommandMapNode> _nodes;
|
private readonly ConcurrentDictionary<string, CommandMapNode> _nodes;
|
||||||
private readonly string _name;
|
private readonly string _name;
|
||||||
private readonly object _lockObj = new object();
|
private readonly object _lockObj = new object();
|
||||||
private ImmutableArray<Command> _commands;
|
private ImmutableArray<CommandInfo> _commands;
|
||||||
|
|
||||||
public bool IsEmpty => _commands.Length == 0 && _nodes.Count == 0;
|
public bool IsEmpty => _commands.Length == 0 && _nodes.Count == 0;
|
||||||
|
|
||||||
@@ -17,10 +17,10 @@ namespace Discord.Commands
|
|||||||
{
|
{
|
||||||
_name = name;
|
_name = name;
|
||||||
_nodes = new ConcurrentDictionary<string, CommandMapNode>();
|
_nodes = new ConcurrentDictionary<string, CommandMapNode>();
|
||||||
_commands = ImmutableArray.Create<Command>();
|
_commands = ImmutableArray.Create<CommandInfo>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddCommand(string text, int index, Command command)
|
public void AddCommand(string text, int index, CommandInfo command)
|
||||||
{
|
{
|
||||||
int nextSpace = text.IndexOf(' ', index);
|
int nextSpace = text.IndexOf(' ', index);
|
||||||
string name;
|
string name;
|
||||||
@@ -41,7 +41,7 @@ namespace Discord.Commands
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public void RemoveCommand(string text, int index, Command command)
|
public void RemoveCommand(string text, int index, CommandInfo command)
|
||||||
{
|
{
|
||||||
int nextSpace = text.IndexOf(' ', index);
|
int nextSpace = text.IndexOf(' ', index);
|
||||||
string name;
|
string name;
|
||||||
@@ -68,7 +68,7 @@ namespace Discord.Commands
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<Command> GetCommands(string text, int index)
|
public IEnumerable<CommandInfo> GetCommands(string text, int index)
|
||||||
{
|
{
|
||||||
int nextSpace = text.IndexOf(' ', index);
|
int nextSpace = text.IndexOf(' ', index);
|
||||||
string name;
|
string name;
|
||||||
|
|||||||
15
src/Discord.Net.Commands/ModuleBase.cs
Normal file
15
src/Discord.Net.Commands/ModuleBase.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Discord.Commands
|
||||||
|
{
|
||||||
|
public abstract class ModuleBase
|
||||||
|
{
|
||||||
|
public IDiscordClient Client { get; internal set; }
|
||||||
|
public CommandContext Context { get; internal set; }
|
||||||
|
|
||||||
|
protected virtual async Task ReplyAsync(string message, bool isTTS = false, RequestOptions options = null)
|
||||||
|
{
|
||||||
|
await Context.Channel.SendMessageAsync(message, isTTS, options).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
@@ -6,26 +7,31 @@ using System.Reflection;
|
|||||||
namespace Discord.Commands
|
namespace Discord.Commands
|
||||||
{
|
{
|
||||||
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
|
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
|
||||||
public class Module
|
public class ModuleInfo
|
||||||
{
|
{
|
||||||
|
internal readonly Func<ModuleBase> _builder;
|
||||||
|
|
||||||
public TypeInfo Source { get; }
|
public TypeInfo Source { get; }
|
||||||
public CommandService Service { get; }
|
public CommandService Service { get; }
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
public string Prefix { get; }
|
public string Prefix { get; }
|
||||||
public string Summary { get; }
|
public string Summary { get; }
|
||||||
public string Remarks { get; }
|
public string Remarks { get; }
|
||||||
public IEnumerable<Command> Commands { get; }
|
public IEnumerable<CommandInfo> Commands { get; }
|
||||||
internal object Instance { get; }
|
|
||||||
|
|
||||||
public IReadOnlyList<PreconditionAttribute> Preconditions { get; }
|
public IReadOnlyList<PreconditionAttribute> Preconditions { get; }
|
||||||
|
|
||||||
internal Module(TypeInfo source, CommandService service, object instance, ModuleAttribute moduleAttr, IDependencyMap dependencyMap)
|
internal ModuleInfo(TypeInfo source, CommandService service, IDependencyMap dependencyMap)
|
||||||
{
|
{
|
||||||
Source = source;
|
Source = source;
|
||||||
Service = service;
|
Service = service;
|
||||||
Name = source.Name;
|
Name = source.Name;
|
||||||
Prefix = moduleAttr.Prefix ?? "";
|
_builder = ReflectionUtils.CreateBuilder<ModuleBase>(source, Service, dependencyMap);
|
||||||
Instance = instance;
|
|
||||||
|
var groupAttr = source.GetCustomAttribute<GroupAttribute>();
|
||||||
|
if (groupAttr != null)
|
||||||
|
Prefix = groupAttr.Prefix;
|
||||||
|
else
|
||||||
|
Prefix = "";
|
||||||
|
|
||||||
var nameAttr = source.GetCustomAttribute<NameAttribute>();
|
var nameAttr = source.GetCustomAttribute<NameAttribute>();
|
||||||
if (nameAttr != null)
|
if (nameAttr != null)
|
||||||
@@ -39,20 +45,19 @@ namespace Discord.Commands
|
|||||||
if (remarksAttr != null)
|
if (remarksAttr != null)
|
||||||
Remarks = remarksAttr.Text;
|
Remarks = remarksAttr.Text;
|
||||||
|
|
||||||
List<Command> commands = new List<Command>();
|
List<CommandInfo> commands = new List<CommandInfo>();
|
||||||
SearchClass(source, instance, commands, Prefix, dependencyMap);
|
SearchClass(source, commands, Prefix, dependencyMap);
|
||||||
Commands = commands;
|
Commands = commands;
|
||||||
|
|
||||||
Preconditions = BuildPreconditions();
|
Preconditions = Source.GetCustomAttributes<PreconditionAttribute>().ToImmutableArray();
|
||||||
}
|
}
|
||||||
|
private void SearchClass(TypeInfo parentType, List<CommandInfo> commands, string groupPrefix, IDependencyMap dependencyMap)
|
||||||
private void SearchClass(TypeInfo parentType, object instance, List<Command> commands, string groupPrefix, IDependencyMap dependencyMap)
|
|
||||||
{
|
{
|
||||||
foreach (var method in parentType.DeclaredMethods)
|
foreach (var method in parentType.DeclaredMethods)
|
||||||
{
|
{
|
||||||
var cmdAttr = method.GetCustomAttribute<CommandAttribute>();
|
var cmdAttr = method.GetCustomAttribute<CommandAttribute>();
|
||||||
if (cmdAttr != null)
|
if (cmdAttr != null)
|
||||||
commands.Add(new Command(method, this, instance, cmdAttr, groupPrefix));
|
commands.Add(new CommandInfo(method, this, cmdAttr, groupPrefix));
|
||||||
}
|
}
|
||||||
foreach (var type in parentType.DeclaredNestedTypes)
|
foreach (var type in parentType.DeclaredNestedTypes)
|
||||||
{
|
{
|
||||||
@@ -66,15 +71,13 @@ namespace Discord.Commands
|
|||||||
else
|
else
|
||||||
nextGroupPrefix = groupAttrib.Prefix ?? type.Name.ToLowerInvariant();
|
nextGroupPrefix = groupAttrib.Prefix ?? type.Name.ToLowerInvariant();
|
||||||
|
|
||||||
SearchClass(type, ReflectionUtils.CreateObject(type, Service, dependencyMap), commands, nextGroupPrefix, dependencyMap);
|
SearchClass(type, commands, nextGroupPrefix, dependencyMap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private IReadOnlyList<PreconditionAttribute> BuildPreconditions()
|
internal ModuleBase CreateInstance()
|
||||||
{
|
=> _builder();
|
||||||
return Source.GetCustomAttributes<PreconditionAttribute>().ToImmutableArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString() => Name;
|
public override string ToString() => Name;
|
||||||
private string DebuggerDisplay => Name;
|
private string DebuggerDisplay => Name;
|
||||||
@@ -13,7 +13,7 @@ namespace Discord.Commands
|
|||||||
static PrimitiveParsers()
|
static PrimitiveParsers()
|
||||||
{
|
{
|
||||||
var parserBuilder = ImmutableDictionary.CreateBuilder<Type, Delegate>();
|
var parserBuilder = ImmutableDictionary.CreateBuilder<Type, Delegate>();
|
||||||
parserBuilder[typeof(string)] = (TryParseDelegate<string>)delegate(string str, out string value) { value = str; return true; };
|
parserBuilder[typeof(bool)] = (TryParseDelegate<bool>)bool.TryParse;
|
||||||
parserBuilder[typeof(sbyte)] = (TryParseDelegate<sbyte>)sbyte.TryParse;
|
parserBuilder[typeof(sbyte)] = (TryParseDelegate<sbyte>)sbyte.TryParse;
|
||||||
parserBuilder[typeof(byte)] = (TryParseDelegate<byte>)byte.TryParse;
|
parserBuilder[typeof(byte)] = (TryParseDelegate<byte>)byte.TryParse;
|
||||||
parserBuilder[typeof(short)] = (TryParseDelegate<short>)short.TryParse;
|
parserBuilder[typeof(short)] = (TryParseDelegate<short>)short.TryParse;
|
||||||
@@ -27,6 +27,12 @@ namespace Discord.Commands
|
|||||||
parserBuilder[typeof(decimal)] = (TryParseDelegate<decimal>)decimal.TryParse;
|
parserBuilder[typeof(decimal)] = (TryParseDelegate<decimal>)decimal.TryParse;
|
||||||
parserBuilder[typeof(DateTime)] = (TryParseDelegate<DateTime>)DateTime.TryParse;
|
parserBuilder[typeof(DateTime)] = (TryParseDelegate<DateTime>)DateTime.TryParse;
|
||||||
parserBuilder[typeof(DateTimeOffset)] = (TryParseDelegate<DateTimeOffset>)DateTimeOffset.TryParse;
|
parserBuilder[typeof(DateTimeOffset)] = (TryParseDelegate<DateTimeOffset>)DateTimeOffset.TryParse;
|
||||||
|
parserBuilder[typeof(char)] = (TryParseDelegate<char>)char.TryParse;
|
||||||
|
parserBuilder[typeof(string)] = (TryParseDelegate<string>)delegate (string str, out string value)
|
||||||
|
{
|
||||||
|
value = str;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
_parsers = parserBuilder.ToImmutable();
|
_parsers = parserBuilder.ToImmutable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,23 +9,21 @@ namespace Discord.Commands
|
|||||||
internal class ChannelTypeReader<T> : TypeReader
|
internal class ChannelTypeReader<T> : TypeReader
|
||||||
where T : class, IChannel
|
where T : class, IChannel
|
||||||
{
|
{
|
||||||
public override async Task<TypeReaderResult> Read(IUserMessage context, string input)
|
public override async Task<TypeReaderResult> Read(CommandContext context, string input)
|
||||||
{
|
{
|
||||||
var guild = (context.Channel as IGuildChannel)?.Guild;
|
if (context.Guild != null)
|
||||||
|
|
||||||
if (guild != null)
|
|
||||||
{
|
{
|
||||||
var results = new Dictionary<ulong, TypeReaderValue>();
|
var results = new Dictionary<ulong, TypeReaderValue>();
|
||||||
var channels = await guild.GetChannelsAsync().ConfigureAwait(false);
|
var channels = await context.Guild.GetChannelsAsync(CacheMode.CacheOnly).ConfigureAwait(false);
|
||||||
ulong id;
|
ulong id;
|
||||||
|
|
||||||
//By Mention (1.0)
|
//By Mention (1.0)
|
||||||
if (MentionUtils.TryParseChannel(input, out id))
|
if (MentionUtils.TryParseChannel(input, out id))
|
||||||
AddResult(results, await guild.GetChannelAsync(id).ConfigureAwait(false) as T, 1.00f);
|
AddResult(results, await context.Guild.GetChannelAsync(id, CacheMode.CacheOnly).ConfigureAwait(false) as T, 1.00f);
|
||||||
|
|
||||||
//By Id (0.9)
|
//By Id (0.9)
|
||||||
if (ulong.TryParse(input, NumberStyles.None, CultureInfo.InvariantCulture, out id))
|
if (ulong.TryParse(input, NumberStyles.None, CultureInfo.InvariantCulture, out id))
|
||||||
AddResult(results, await guild.GetChannelAsync(id).ConfigureAwait(false) as T, 0.90f);
|
AddResult(results, await context.Guild.GetChannelAsync(id, CacheMode.CacheOnly).ConfigureAwait(false) as T, 0.90f);
|
||||||
|
|
||||||
//By Name (0.7-0.8)
|
//By Name (0.7-0.8)
|
||||||
foreach (var channel in channels.Where(x => string.Equals(input, x.Name, StringComparison.OrdinalIgnoreCase)))
|
foreach (var channel in channels.Where(x => string.Equals(input, x.Name, StringComparison.OrdinalIgnoreCase)))
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ namespace Discord.Commands
|
|||||||
_enumsByValue = byValueBuilder.ToImmutable();
|
_enumsByValue = byValueBuilder.ToImmutable();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task<TypeReaderResult> Read(IUserMessage context, string input)
|
public override Task<TypeReaderResult> Read(CommandContext context, string input)
|
||||||
{
|
{
|
||||||
T baseValue;
|
T baseValue;
|
||||||
object enumValue;
|
object enumValue;
|
||||||
|
|||||||
@@ -6,19 +6,19 @@ namespace Discord.Commands
|
|||||||
internal class MessageTypeReader<T> : TypeReader
|
internal class MessageTypeReader<T> : TypeReader
|
||||||
where T : class, IMessage
|
where T : class, IMessage
|
||||||
{
|
{
|
||||||
public override Task<TypeReaderResult> Read(IUserMessage context, string input)
|
public override async Task<TypeReaderResult> Read(CommandContext context, string input)
|
||||||
{
|
{
|
||||||
ulong id;
|
ulong id;
|
||||||
|
|
||||||
//By Id (1.0)
|
//By Id (1.0)
|
||||||
if (ulong.TryParse(input, NumberStyles.None, CultureInfo.InvariantCulture, out id))
|
if (ulong.TryParse(input, NumberStyles.None, CultureInfo.InvariantCulture, out id))
|
||||||
{
|
{
|
||||||
var msg = context.Channel.GetCachedMessage(id) as T;
|
var msg = await context.Channel.GetMessageAsync(id, CacheMode.CacheOnly).ConfigureAwait(false) as T;
|
||||||
if (msg != null)
|
if (msg != null)
|
||||||
return Task.FromResult(TypeReaderResult.FromSuccess(msg));
|
return TypeReaderResult.FromSuccess(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.FromResult(TypeReaderResult.FromError(CommandError.ObjectNotFound, "Message not found."));
|
return TypeReaderResult.FromError(CommandError.ObjectNotFound, "Message not found.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,23 +9,22 @@ namespace Discord.Commands
|
|||||||
internal class RoleTypeReader<T> : TypeReader
|
internal class RoleTypeReader<T> : TypeReader
|
||||||
where T : class, IRole
|
where T : class, IRole
|
||||||
{
|
{
|
||||||
public override Task<TypeReaderResult> Read(IUserMessage context, string input)
|
public override Task<TypeReaderResult> Read(CommandContext context, string input)
|
||||||
{
|
{
|
||||||
var guild = (context.Channel as IGuildChannel)?.Guild;
|
|
||||||
ulong id;
|
ulong id;
|
||||||
|
|
||||||
if (guild != null)
|
if (context.Guild != null)
|
||||||
{
|
{
|
||||||
var results = new Dictionary<ulong, TypeReaderValue>();
|
var results = new Dictionary<ulong, TypeReaderValue>();
|
||||||
var roles = guild.Roles;
|
var roles = context.Guild.Roles;
|
||||||
|
|
||||||
//By Mention (1.0)
|
//By Mention (1.0)
|
||||||
if (MentionUtils.TryParseRole(input, out id))
|
if (MentionUtils.TryParseRole(input, out id))
|
||||||
AddResult(results, guild.GetRole(id) as T, 1.00f);
|
AddResult(results, context.Guild.GetRole(id) as T, 1.00f);
|
||||||
|
|
||||||
//By Id (0.9)
|
//By Id (0.9)
|
||||||
if (ulong.TryParse(input, NumberStyles.None, CultureInfo.InvariantCulture, out id))
|
if (ulong.TryParse(input, NumberStyles.None, CultureInfo.InvariantCulture, out id))
|
||||||
AddResult(results, guild.GetRole(id) as T, 0.90f);
|
AddResult(results, context.Guild.GetRole(id) as T, 0.90f);
|
||||||
|
|
||||||
//By Name (0.7-0.8)
|
//By Name (0.7-0.8)
|
||||||
foreach (var role in roles.Where(x => string.Equals(input, x.Name, StringComparison.OrdinalIgnoreCase)))
|
foreach (var role in roles.Where(x => string.Equals(input, x.Name, StringComparison.OrdinalIgnoreCase)))
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ namespace Discord.Commands
|
|||||||
_tryParse = PrimitiveParsers.Get<T>();
|
_tryParse = PrimitiveParsers.Get<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task<TypeReaderResult> Read(IUserMessage context, string input)
|
public override Task<TypeReaderResult> Read(CommandContext context, string input)
|
||||||
{
|
{
|
||||||
T value;
|
T value;
|
||||||
if (_tryParse(input, out value))
|
if (_tryParse(input, out value))
|
||||||
|
|||||||
@@ -4,6 +4,6 @@ namespace Discord.Commands
|
|||||||
{
|
{
|
||||||
public abstract class TypeReader
|
public abstract class TypeReader
|
||||||
{
|
{
|
||||||
public abstract Task<TypeReaderResult> Read(IUserMessage context, string input);
|
public abstract Task<TypeReaderResult> Read(CommandContext context, string input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -9,33 +10,32 @@ namespace Discord.Commands
|
|||||||
internal class UserTypeReader<T> : TypeReader
|
internal class UserTypeReader<T> : TypeReader
|
||||||
where T : class, IUser
|
where T : class, IUser
|
||||||
{
|
{
|
||||||
public override async Task<TypeReaderResult> Read(IUserMessage context, string input)
|
public override async Task<TypeReaderResult> Read(CommandContext context, string input)
|
||||||
{
|
{
|
||||||
var results = new Dictionary<ulong, TypeReaderValue>();
|
var results = new Dictionary<ulong, TypeReaderValue>();
|
||||||
var guild = (context.Channel as IGuildChannel)?.Guild;
|
IReadOnlyCollection<IUser> channelUsers = (await context.Channel.GetUsersAsync(CacheMode.CacheOnly).Flatten().ConfigureAwait(false)).ToArray(); //TODO: must be a better way?
|
||||||
IReadOnlyCollection<IUser> channelUsers = await context.Channel.GetUsersAsync().ConfigureAwait(false);
|
|
||||||
IReadOnlyCollection<IGuildUser> guildUsers = null;
|
IReadOnlyCollection<IGuildUser> guildUsers = null;
|
||||||
ulong id;
|
ulong id;
|
||||||
|
|
||||||
if (guild != null)
|
if (context.Guild != null)
|
||||||
guildUsers = await guild.GetUsersAsync().ConfigureAwait(false);
|
guildUsers = await context.Guild.GetUsersAsync(CacheMode.CacheOnly).ConfigureAwait(false);
|
||||||
|
|
||||||
//By Mention (1.0)
|
//By Mention (1.0)
|
||||||
if (MentionUtils.TryParseUser(input, out id))
|
if (MentionUtils.TryParseUser(input, out id))
|
||||||
{
|
{
|
||||||
if (guild != null)
|
if (context.Guild != null)
|
||||||
AddResult(results, await guild.GetUserAsync(id).ConfigureAwait(false) as T, 1.00f);
|
AddResult(results, await context.Guild.GetUserAsync(id, CacheMode.CacheOnly).ConfigureAwait(false) as T, 1.00f);
|
||||||
else
|
else
|
||||||
AddResult(results, await context.Channel.GetUserAsync(id).ConfigureAwait(false) as T, 1.00f);
|
AddResult(results, await context.Channel.GetUserAsync(id, CacheMode.CacheOnly).ConfigureAwait(false) as T, 1.00f);
|
||||||
}
|
}
|
||||||
|
|
||||||
//By Id (0.9)
|
//By Id (0.9)
|
||||||
if (ulong.TryParse(input, NumberStyles.None, CultureInfo.InvariantCulture, out id))
|
if (ulong.TryParse(input, NumberStyles.None, CultureInfo.InvariantCulture, out id))
|
||||||
{
|
{
|
||||||
if (guild != null)
|
if (context.Guild != null)
|
||||||
AddResult(results, await guild.GetUserAsync(id).ConfigureAwait(false) as T, 0.90f);
|
AddResult(results, await context.Guild.GetUserAsync(id, CacheMode.CacheOnly).ConfigureAwait(false) as T, 0.90f);
|
||||||
else
|
else
|
||||||
AddResult(results, await context.Channel.GetUserAsync(id).ConfigureAwait(false) as T, 0.90f);
|
AddResult(results, await context.Channel.GetUserAsync(id, CacheMode.CacheOnly).ConfigureAwait(false) as T, 0.90f);
|
||||||
}
|
}
|
||||||
|
|
||||||
//By Username + Discriminator (0.7-0.85)
|
//By Username + Discriminator (0.7-0.85)
|
||||||
@@ -75,7 +75,7 @@ namespace Discord.Commands
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (results.Count > 0)
|
if (results.Count > 0)
|
||||||
return TypeReaderResult.FromSuccess(results.Values.ToArray());
|
return TypeReaderResult.FromSuccess(results.Values.ToImmutableArray());
|
||||||
return TypeReaderResult.FromError(CommandError.ObjectNotFound, "User not found.");
|
return TypeReaderResult.FromError(CommandError.ObjectNotFound, "User not found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,10 @@ namespace Discord.Commands
|
|||||||
{
|
{
|
||||||
internal class ReflectionUtils
|
internal class ReflectionUtils
|
||||||
{
|
{
|
||||||
internal static object CreateObject(TypeInfo typeInfo, CommandService service, IDependencyMap map = null)
|
internal static T CreateObject<T>(TypeInfo typeInfo, CommandService service, IDependencyMap map = null)
|
||||||
|
=> CreateBuilder<T>(typeInfo, service, map)();
|
||||||
|
|
||||||
|
internal static Func<T> CreateBuilder<T>(TypeInfo typeInfo, CommandService service, IDependencyMap map = null)
|
||||||
{
|
{
|
||||||
var constructors = typeInfo.DeclaredConstructors.Where(x => !x.IsStatic).ToArray();
|
var constructors = typeInfo.DeclaredConstructors.Where(x => !x.IsStatic).ToArray();
|
||||||
if (constructors.Length == 0)
|
if (constructors.Length == 0)
|
||||||
@@ -14,7 +17,7 @@ namespace Discord.Commands
|
|||||||
else if (constructors.Length > 1)
|
else if (constructors.Length > 1)
|
||||||
throw new InvalidOperationException($"Multiple constructors found for \"{typeInfo.FullName}\"");
|
throw new InvalidOperationException($"Multiple constructors found for \"{typeInfo.FullName}\"");
|
||||||
|
|
||||||
var constructor = constructors[0];
|
var constructor = constructors[0];
|
||||||
ParameterInfo[] parameters = constructor.GetParameters();
|
ParameterInfo[] parameters = constructor.GetParameters();
|
||||||
object[] args = new object[parameters.Length];
|
object[] args = new object[parameters.Length];
|
||||||
|
|
||||||
@@ -34,14 +37,17 @@ namespace Discord.Commands
|
|||||||
args[i] = arg;
|
args[i] = arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
return () =>
|
||||||
{
|
{
|
||||||
return constructor.Invoke(args);
|
try
|
||||||
}
|
{
|
||||||
catch (Exception ex)
|
return (T)constructor.Invoke(args);
|
||||||
{
|
}
|
||||||
throw new Exception($"Failed to create \"{typeInfo.FullName}\"", ex);
|
catch (Exception ex)
|
||||||
}
|
{
|
||||||
|
throw new Exception($"Failed to create \"{typeInfo.FullName}\"", ex);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,14 +7,14 @@ namespace Discord.Commands
|
|||||||
public struct SearchResult : IResult
|
public struct SearchResult : IResult
|
||||||
{
|
{
|
||||||
public string Text { get; }
|
public string Text { get; }
|
||||||
public IReadOnlyList<Command> Commands { get; }
|
public IReadOnlyList<CommandInfo> Commands { get; }
|
||||||
|
|
||||||
public CommandError? Error { get; }
|
public CommandError? Error { get; }
|
||||||
public string ErrorReason { get; }
|
public string ErrorReason { get; }
|
||||||
|
|
||||||
public bool IsSuccess => !Error.HasValue;
|
public bool IsSuccess => !Error.HasValue;
|
||||||
|
|
||||||
private SearchResult(string text, IReadOnlyList<Command> commands, CommandError? error, string errorReason)
|
private SearchResult(string text, IReadOnlyList<CommandInfo> commands, CommandError? error, string errorReason)
|
||||||
{
|
{
|
||||||
Text = text;
|
Text = text;
|
||||||
Commands = commands;
|
Commands = commands;
|
||||||
@@ -22,7 +22,7 @@ namespace Discord.Commands
|
|||||||
ErrorReason = errorReason;
|
ErrorReason = errorReason;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SearchResult FromSuccess(string text, IReadOnlyList<Command> commands)
|
public static SearchResult FromSuccess(string text, IReadOnlyList<CommandInfo> commands)
|
||||||
=> new SearchResult(text, commands, null, null);
|
=> new SearchResult(text, commands, null, null);
|
||||||
public static SearchResult FromError(CommandError error, string reason)
|
public static SearchResult FromError(CommandError error, string reason)
|
||||||
=> new SearchResult(null, null, error, reason);
|
=> new SearchResult(null, null, error, reason);
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace Discord.Commands
|
namespace Discord.Commands
|
||||||
{
|
{
|
||||||
|
|||||||
9
src/Discord.Net.Commands/RunMode.cs
Normal file
9
src/Discord.Net.Commands/RunMode.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
namespace Discord.Commands
|
||||||
|
{
|
||||||
|
public enum RunMode
|
||||||
|
{
|
||||||
|
Sync,
|
||||||
|
Mixed,
|
||||||
|
Async
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,24 +13,22 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"buildOptions": {
|
|
||||||
"allowUnsafe": true,
|
|
||||||
"warningsAsErrors": false,
|
|
||||||
"xmlDoc": true
|
|
||||||
},
|
|
||||||
|
|
||||||
"configurations": {
|
"configurations": {
|
||||||
"Release": {
|
"Release": {
|
||||||
"buildOptions": {
|
"buildOptions": {
|
||||||
"define": [ "RELEASE" ],
|
"define": [ "RELEASE" ],
|
||||||
"nowarn": [ "CS1573", "CS1591" ],
|
"nowarn": [ "CS1573", "CS1591" ],
|
||||||
"optimize": true
|
"optimize": true,
|
||||||
|
"warningsAsErrors": true,
|
||||||
|
"xmlDoc": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Discord.Net": "1.0.0-*"
|
"Discord.Net.Core": {
|
||||||
|
"target": "project"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"frameworks": {
|
"frameworks": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
namespace Discord.API
|
namespace Discord.API
|
||||||
{
|
{
|
||||||
internal static class CDN
|
public static class CDN
|
||||||
{
|
{
|
||||||
public static string GetApplicationIconUrl(ulong appId, string iconId)
|
public static string GetApplicationIconUrl(ulong appId, string iconId)
|
||||||
=> iconId != null ? $"{DiscordConfig.CDNUrl}app-icons/{appId}/{iconId}.jpg" : null;
|
=> iconId != null ? $"{DiscordConfig.CDNUrl}app-icons/{appId}/{iconId}.jpg" : null;
|
||||||
@@ -12,5 +12,7 @@
|
|||||||
=> splashId != null ? $"{DiscordConfig.CDNUrl}splashes/{guildId}/{splashId}.jpg" : null;
|
=> splashId != null ? $"{DiscordConfig.CDNUrl}splashes/{guildId}/{splashId}.jpg" : null;
|
||||||
public static string GetChannelIconUrl(ulong channelId, string iconId)
|
public static string GetChannelIconUrl(ulong channelId, string iconId)
|
||||||
=> iconId != null ? $"{DiscordConfig.CDNUrl}channel-icons/{channelId}/{iconId}.jpg" : null;
|
=> iconId != null ? $"{DiscordConfig.CDNUrl}channel-icons/{channelId}/{iconId}.jpg" : null;
|
||||||
|
public static string GetEmojiUrl(ulong emojiId)
|
||||||
|
=> $"{DiscordConfig.CDNUrl}emojis/{emojiId}.png";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -11,13 +11,14 @@ namespace Discord.API
|
|||||||
public string[] RPCOrigins { get; set; }
|
public string[] RPCOrigins { get; set; }
|
||||||
[JsonProperty("name")]
|
[JsonProperty("name")]
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
[JsonProperty("flags"), Int53]
|
|
||||||
public ulong Flags { get; set; }
|
|
||||||
[JsonProperty("owner")]
|
|
||||||
public User Owner { get; set; }
|
|
||||||
[JsonProperty("id")]
|
[JsonProperty("id")]
|
||||||
public ulong Id { get; set; }
|
public ulong Id { get; set; }
|
||||||
[JsonProperty("icon")]
|
[JsonProperty("icon")]
|
||||||
public string Icon { get; set; }
|
public string Icon { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("flags"), Int53]
|
||||||
|
public Optional<ulong> Flags { get; set; }
|
||||||
|
[JsonProperty("owner")]
|
||||||
|
public Optional<User> Owner { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -12,6 +12,8 @@ namespace Discord.API
|
|||||||
public MessageType Type { get; set; }
|
public MessageType Type { get; set; }
|
||||||
[JsonProperty("channel_id")]
|
[JsonProperty("channel_id")]
|
||||||
public ulong ChannelId { get; set; }
|
public ulong ChannelId { get; set; }
|
||||||
|
[JsonProperty("webhook_id")]
|
||||||
|
public Optional<ulong> WebhookId { get; set; }
|
||||||
[JsonProperty("author")]
|
[JsonProperty("author")]
|
||||||
public Optional<User> Author { get; set; }
|
public Optional<User> Author { get; set; }
|
||||||
[JsonProperty("content")]
|
[JsonProperty("content")]
|
||||||
@@ -25,7 +27,9 @@ namespace Discord.API
|
|||||||
[JsonProperty("mention_everyone")]
|
[JsonProperty("mention_everyone")]
|
||||||
public Optional<bool> MentionEveryone { get; set; }
|
public Optional<bool> MentionEveryone { get; set; }
|
||||||
[JsonProperty("mentions")]
|
[JsonProperty("mentions")]
|
||||||
public Optional<User[]> Mentions { get; set; }
|
public Optional<ObjectOrId<User>[]> UserMentions { get; set; }
|
||||||
|
[JsonProperty("mention_roles")]
|
||||||
|
public Optional<ulong[]> RoleMentions { get; set; }
|
||||||
[JsonProperty("attachments")]
|
[JsonProperty("attachments")]
|
||||||
public Optional<Attachment[]> Attachments { get; set; }
|
public Optional<Attachment[]> Attachments { get; set; }
|
||||||
[JsonProperty("embeds")]
|
[JsonProperty("embeds")]
|
||||||
@@ -5,6 +5,7 @@ namespace Discord.API
|
|||||||
{
|
{
|
||||||
Friend = 1,
|
Friend = 1,
|
||||||
Blocked = 2,
|
Blocked = 2,
|
||||||
Pending = 4
|
IncomingPending = 3,
|
||||||
|
OutgoingPending = 4
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13,6 +13,8 @@ namespace Discord.API
|
|||||||
public uint Color { get; set; }
|
public uint Color { get; set; }
|
||||||
[JsonProperty("hoist")]
|
[JsonProperty("hoist")]
|
||||||
public bool Hoist { get; set; }
|
public bool Hoist { get; set; }
|
||||||
|
[JsonProperty("mentionable")]
|
||||||
|
public bool Mentionable { get; set; }
|
||||||
[JsonProperty("position")]
|
[JsonProperty("position")]
|
||||||
public int Position { get; set; }
|
public int Position { get; set; }
|
||||||
[JsonProperty("permissions"), Int53]
|
[JsonProperty("permissions"), Int53]
|
||||||
1140
src/Discord.Net.Core/API/DiscordRestApiClient.cs
Normal file
1140
src/Discord.Net.Core/API/DiscordRestApiClient.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace Discord.API
|
namespace Discord.API
|
||||||
{
|
{
|
||||||
internal struct Image
|
public struct Image
|
||||||
{
|
{
|
||||||
public Stream Stream { get; }
|
public Stream Stream { get; }
|
||||||
public string Hash { get; }
|
public string Hash { get; }
|
||||||
19
src/Discord.Net.Core/API/ObjectOrId.cs
Normal file
19
src/Discord.Net.Core/API/ObjectOrId.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
namespace Discord.API
|
||||||
|
{
|
||||||
|
public struct ObjectOrId<T>
|
||||||
|
{
|
||||||
|
public ulong Id { get; }
|
||||||
|
public T Object { get; }
|
||||||
|
|
||||||
|
public ObjectOrId(ulong id)
|
||||||
|
{
|
||||||
|
Id = id;
|
||||||
|
Object = default(T);
|
||||||
|
}
|
||||||
|
public ObjectOrId(T obj)
|
||||||
|
{
|
||||||
|
Id = 0;
|
||||||
|
Object = obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/Discord.Net.Core/API/Rest/CreateChannelInviteParams.cs
Normal file
16
src/Discord.Net.Core/API/Rest/CreateChannelInviteParams.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#pragma warning disable CS1591
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Discord.API.Rest
|
||||||
|
{
|
||||||
|
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
|
||||||
|
public class CreateChannelInviteParams
|
||||||
|
{
|
||||||
|
[JsonProperty("max_age")]
|
||||||
|
public Optional<int> MaxAge { get; set; }
|
||||||
|
[JsonProperty("max_uses")]
|
||||||
|
public Optional<int> MaxUses { get; set; }
|
||||||
|
[JsonProperty("temporary")]
|
||||||
|
public Optional<bool> IsTemporary { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,8 +7,11 @@ namespace Discord.API.Rest
|
|||||||
public class CreateDMChannelParams
|
public class CreateDMChannelParams
|
||||||
{
|
{
|
||||||
[JsonProperty("recipient_id")]
|
[JsonProperty("recipient_id")]
|
||||||
internal ulong _recipientId { get; set; }
|
public ulong RecipientId { get; }
|
||||||
public ulong RecipientId { set { _recipientId = value; } }
|
|
||||||
public IUser Recipient { set { _recipientId = value.Id; } }
|
public CreateDMChannelParams(ulong recipientId)
|
||||||
|
{
|
||||||
|
RecipientId = recipientId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
8
src/Discord.Net.Core/API/Rest/CreateGuildBanParams.cs
Normal file
8
src/Discord.Net.Core/API/Rest/CreateGuildBanParams.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#pragma warning disable CS1591
|
||||||
|
namespace Discord.API.Rest
|
||||||
|
{
|
||||||
|
public class CreateGuildBanParams
|
||||||
|
{
|
||||||
|
public Optional<int> DeleteMessageDays { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
23
src/Discord.Net.Core/API/Rest/CreateGuildChannelParams.cs
Normal file
23
src/Discord.Net.Core/API/Rest/CreateGuildChannelParams.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#pragma warning disable CS1591
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Discord.API.Rest
|
||||||
|
{
|
||||||
|
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
|
||||||
|
public class CreateGuildChannelParams
|
||||||
|
{
|
||||||
|
[JsonProperty("name")]
|
||||||
|
public string Name { get; }
|
||||||
|
[JsonProperty("type")]
|
||||||
|
public ChannelType Type { get; }
|
||||||
|
|
||||||
|
[JsonProperty("bitrate")]
|
||||||
|
public Optional<int> Bitrate { get; set; }
|
||||||
|
|
||||||
|
public CreateGuildChannelParams(string name, ChannelType type)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
Type = type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,9 +7,14 @@ namespace Discord.API.Rest
|
|||||||
public class CreateGuildIntegrationParams
|
public class CreateGuildIntegrationParams
|
||||||
{
|
{
|
||||||
[JsonProperty("id")]
|
[JsonProperty("id")]
|
||||||
public ulong Id { internal get; set; }
|
public ulong Id { get; }
|
||||||
|
|
||||||
[JsonProperty("type")]
|
[JsonProperty("type")]
|
||||||
public string Type { internal get; set; }
|
public string Type { get; }
|
||||||
|
|
||||||
|
public CreateGuildIntegrationParams(ulong id, string type)
|
||||||
|
{
|
||||||
|
Id = id;
|
||||||
|
Type = type;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
#pragma warning disable CS1591
|
#pragma warning disable CS1591
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace Discord.API.Rest
|
namespace Discord.API.Rest
|
||||||
{
|
{
|
||||||
@@ -8,13 +7,17 @@ namespace Discord.API.Rest
|
|||||||
public class CreateGuildParams
|
public class CreateGuildParams
|
||||||
{
|
{
|
||||||
[JsonProperty("name")]
|
[JsonProperty("name")]
|
||||||
public string Name { internal get; set; }
|
public string Name { get; }
|
||||||
|
|
||||||
[JsonProperty("region")]
|
[JsonProperty("region")]
|
||||||
public string Region { internal get; set; }
|
public string RegionId { get; }
|
||||||
|
|
||||||
[JsonProperty("icon")]
|
[JsonProperty("icon")]
|
||||||
internal Optional<Image?> _icon { get; set; }
|
public Optional<Image?> Icon { get; set; }
|
||||||
public Stream Icon { set { _icon = value != null ? new Image(value) : (Image?)null; } }
|
|
||||||
|
public CreateGuildParams(string name, string regionId)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
RegionId = regionId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
22
src/Discord.Net.Core/API/Rest/CreateMessageParams.cs
Normal file
22
src/Discord.Net.Core/API/Rest/CreateMessageParams.cs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#pragma warning disable CS1591
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Discord.API.Rest
|
||||||
|
{
|
||||||
|
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
|
||||||
|
public class CreateMessageParams
|
||||||
|
{
|
||||||
|
[JsonProperty("content")]
|
||||||
|
public string Content { get; }
|
||||||
|
|
||||||
|
[JsonProperty("nonce")]
|
||||||
|
public Optional<string> Nonce { get; set; }
|
||||||
|
[JsonProperty("tts")]
|
||||||
|
public Optional<bool> IsTTS { get; set; }
|
||||||
|
|
||||||
|
public CreateMessageParams(string content)
|
||||||
|
{
|
||||||
|
Content = content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
17
src/Discord.Net.Core/API/Rest/DeleteMessagesParams.cs
Normal file
17
src/Discord.Net.Core/API/Rest/DeleteMessagesParams.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#pragma warning disable CS1591
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Discord.API.Rest
|
||||||
|
{
|
||||||
|
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
|
||||||
|
public class DeleteMessagesParams
|
||||||
|
{
|
||||||
|
[JsonProperty("messages")]
|
||||||
|
public ulong[] MessageIds { get; }
|
||||||
|
|
||||||
|
public DeleteMessagesParams(ulong[] messageIds)
|
||||||
|
{
|
||||||
|
MessageIds = messageIds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/Discord.Net.Core/API/Rest/GetChannelMessagesParams.cs
Normal file
10
src/Discord.Net.Core/API/Rest/GetChannelMessagesParams.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#pragma warning disable CS1591
|
||||||
|
namespace Discord.API.Rest
|
||||||
|
{
|
||||||
|
public class GetChannelMessagesParams
|
||||||
|
{
|
||||||
|
public Optional<int> Limit { get; set; }
|
||||||
|
public Optional<Direction> RelativeDirection { get; set; }
|
||||||
|
public Optional<ulong> RelativeMessageId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
9
src/Discord.Net.Core/API/Rest/GetGuildMembersParams.cs
Normal file
9
src/Discord.Net.Core/API/Rest/GetGuildMembersParams.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#pragma warning disable CS1591
|
||||||
|
namespace Discord.API.Rest
|
||||||
|
{
|
||||||
|
public class GetGuildMembersParams
|
||||||
|
{
|
||||||
|
public Optional<int> Limit { get; set; }
|
||||||
|
public Optional<ulong> AfterUserId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,11 @@ namespace Discord.API.Rest
|
|||||||
public class GuildPruneParams
|
public class GuildPruneParams
|
||||||
{
|
{
|
||||||
[JsonProperty("days")]
|
[JsonProperty("days")]
|
||||||
public int Days { internal get; set; }
|
public int Days { get; }
|
||||||
|
|
||||||
|
public GuildPruneParams(int days)
|
||||||
|
{
|
||||||
|
Days = days;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,10 +7,17 @@ namespace Discord.API.Rest
|
|||||||
public class ModifyChannelPermissionsParams
|
public class ModifyChannelPermissionsParams
|
||||||
{
|
{
|
||||||
[JsonProperty("type")]
|
[JsonProperty("type")]
|
||||||
public string Type { internal get; set; }
|
public string Type { get; }
|
||||||
[JsonProperty("allow")]
|
[JsonProperty("allow")]
|
||||||
public ulong Allow { internal get; set; }
|
public ulong Allow { get; }
|
||||||
[JsonProperty("deny")]
|
[JsonProperty("deny")]
|
||||||
public ulong Deny { internal get; set; }
|
public ulong Deny { get; }
|
||||||
|
|
||||||
|
public ModifyChannelPermissionsParams(string type, ulong allow, ulong deny)
|
||||||
|
{
|
||||||
|
Type = type;
|
||||||
|
Allow = allow;
|
||||||
|
Deny = deny;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,11 @@ namespace Discord.API.Rest
|
|||||||
public class ModifyCurrentUserNickParams
|
public class ModifyCurrentUserNickParams
|
||||||
{
|
{
|
||||||
[JsonProperty("nick")]
|
[JsonProperty("nick")]
|
||||||
public string Nickname { internal get; set; }
|
public string Nickname { get; }
|
||||||
|
|
||||||
|
public ModifyCurrentUserNickParams(string nickname)
|
||||||
|
{
|
||||||
|
Nickname = nickname;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
#pragma warning disable CS1591
|
#pragma warning disable CS1591
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace Discord.API.Rest
|
namespace Discord.API.Rest
|
||||||
{
|
{
|
||||||
@@ -8,11 +7,8 @@ namespace Discord.API.Rest
|
|||||||
public class ModifyCurrentUserParams
|
public class ModifyCurrentUserParams
|
||||||
{
|
{
|
||||||
[JsonProperty("username")]
|
[JsonProperty("username")]
|
||||||
internal Optional<string> _username { get; set; }
|
public Optional<string> Username { get; set; }
|
||||||
public string Username { set { _username = value; } }
|
|
||||||
|
|
||||||
[JsonProperty("avatar")]
|
[JsonProperty("avatar")]
|
||||||
internal Optional<Image> _avatar { get; set; }
|
public Optional<Image> Avatar { get; set; }
|
||||||
public Stream Avatar { set { _avatar = new Image(value); } }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,11 +7,8 @@ namespace Discord.API.Rest
|
|||||||
public class ModifyGuildChannelParams
|
public class ModifyGuildChannelParams
|
||||||
{
|
{
|
||||||
[JsonProperty("name")]
|
[JsonProperty("name")]
|
||||||
internal Optional<string> _name { get; set; }
|
public Optional<string> Name { get; set; }
|
||||||
public string Name { set { _name = value; } }
|
|
||||||
|
|
||||||
[JsonProperty("position")]
|
[JsonProperty("position")]
|
||||||
internal Optional<int> _position { get; set; }
|
public Optional<int> Position { get; set; }
|
||||||
public int Position { set { _position = value; } }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,9 +7,14 @@ namespace Discord.API.Rest
|
|||||||
public class ModifyGuildChannelsParams
|
public class ModifyGuildChannelsParams
|
||||||
{
|
{
|
||||||
[JsonProperty("id")]
|
[JsonProperty("id")]
|
||||||
public ulong Id { internal get; set; }
|
public ulong Id { get; set; }
|
||||||
|
|
||||||
[JsonProperty("position")]
|
[JsonProperty("position")]
|
||||||
public int Position { internal get; set; }
|
public int Position { get; set; }
|
||||||
|
|
||||||
|
public ModifyGuildChannelsParams(ulong id, int position)
|
||||||
|
{
|
||||||
|
Id = id;
|
||||||
|
Position = position;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
14
src/Discord.Net.Core/API/Rest/ModifyGuildEmbedParams.cs
Normal file
14
src/Discord.Net.Core/API/Rest/ModifyGuildEmbedParams.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#pragma warning disable CS1591
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Discord.API.Rest
|
||||||
|
{
|
||||||
|
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
|
||||||
|
public class ModifyGuildEmbedParams
|
||||||
|
{
|
||||||
|
[JsonProperty("enabled")]
|
||||||
|
public Optional<bool> Enabled { get; set; }
|
||||||
|
[JsonProperty("channel")]
|
||||||
|
public Optional<ulong?> ChannelId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#pragma warning disable CS1591
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Discord.API.Rest
|
||||||
|
{
|
||||||
|
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
|
||||||
|
public class ModifyGuildIntegrationParams
|
||||||
|
{
|
||||||
|
[JsonProperty("expire_behavior")]
|
||||||
|
public Optional<int> ExpireBehavior { get; set; }
|
||||||
|
[JsonProperty("expire_grace_period")]
|
||||||
|
public Optional<int> ExpireGracePeriod { get; set; }
|
||||||
|
[JsonProperty("enable_emoticons")]
|
||||||
|
public Optional<bool> EnableEmoticons { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
20
src/Discord.Net.Core/API/Rest/ModifyGuildMemberParams.cs
Normal file
20
src/Discord.Net.Core/API/Rest/ModifyGuildMemberParams.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#pragma warning disable CS1591
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Discord.API.Rest
|
||||||
|
{
|
||||||
|
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
|
||||||
|
public class ModifyGuildMemberParams
|
||||||
|
{
|
||||||
|
[JsonProperty("mute")]
|
||||||
|
public Optional<bool> Mute { get; set; }
|
||||||
|
[JsonProperty("deaf")]
|
||||||
|
public Optional<bool> Deaf { get; set; }
|
||||||
|
[JsonProperty("nick")]
|
||||||
|
public Optional<string> Nickname { get; set; }
|
||||||
|
[JsonProperty("roles")]
|
||||||
|
public Optional<ulong[]> RoleIds { get; set; }
|
||||||
|
[JsonProperty("channel_id")]
|
||||||
|
public Optional<ulong> ChannelId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
30
src/Discord.Net.Core/API/Rest/ModifyGuildParams.cs
Normal file
30
src/Discord.Net.Core/API/Rest/ModifyGuildParams.cs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#pragma warning disable CS1591
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Discord.API.Rest
|
||||||
|
{
|
||||||
|
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
|
||||||
|
public class ModifyGuildParams
|
||||||
|
{
|
||||||
|
[JsonProperty("username")]
|
||||||
|
public Optional<string> Username { get; set; }
|
||||||
|
[JsonProperty("name")]
|
||||||
|
public Optional<string> Name { get; set; }
|
||||||
|
[JsonProperty("region")]
|
||||||
|
public Optional<string> RegionId { get; set; }
|
||||||
|
[JsonProperty("verification_level")]
|
||||||
|
public Optional<VerificationLevel> VerificationLevel { get; set; }
|
||||||
|
[JsonProperty("default_message_notifications")]
|
||||||
|
public Optional<DefaultMessageNotifications> DefaultMessageNotifications { get; set; }
|
||||||
|
[JsonProperty("afk_timeout")]
|
||||||
|
public Optional<int> AfkTimeout { get; set; }
|
||||||
|
[JsonProperty("icon")]
|
||||||
|
public Optional<Image?> Icon { get; set; }
|
||||||
|
[JsonProperty("splash")]
|
||||||
|
public Optional<Image?> Splash { get; set; }
|
||||||
|
[JsonProperty("afk_channel_id")]
|
||||||
|
public Optional<ulong?> AfkChannelId { get; set; }
|
||||||
|
[JsonProperty("owner_id")]
|
||||||
|
public Optional<ulong> OwnerId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
20
src/Discord.Net.Core/API/Rest/ModifyGuildRoleParams.cs
Normal file
20
src/Discord.Net.Core/API/Rest/ModifyGuildRoleParams.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#pragma warning disable CS1591
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Discord.API.Rest
|
||||||
|
{
|
||||||
|
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
|
||||||
|
public class ModifyGuildRoleParams
|
||||||
|
{
|
||||||
|
[JsonProperty("name")]
|
||||||
|
public Optional<string> Name { get; set; }
|
||||||
|
[JsonProperty("permissions")]
|
||||||
|
public Optional<ulong> Permissions { get; set; }
|
||||||
|
[JsonProperty("position")]
|
||||||
|
public Optional<int> Position { get; set; }
|
||||||
|
[JsonProperty("color")]
|
||||||
|
public Optional<uint> Color { get; set; }
|
||||||
|
[JsonProperty("hoist")]
|
||||||
|
public Optional<bool> Hoist { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,11 @@ namespace Discord.API.Rest
|
|||||||
public class ModifyGuildRolesParams : ModifyGuildRoleParams
|
public class ModifyGuildRolesParams : ModifyGuildRoleParams
|
||||||
{
|
{
|
||||||
[JsonProperty("id")]
|
[JsonProperty("id")]
|
||||||
public ulong Id { internal get; set; }
|
public ulong Id { get; }
|
||||||
|
|
||||||
|
public ModifyGuildRolesParams(ulong id)
|
||||||
|
{
|
||||||
|
Id = id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,7 +7,6 @@ namespace Discord.API.Rest
|
|||||||
public class ModifyMessageParams
|
public class ModifyMessageParams
|
||||||
{
|
{
|
||||||
[JsonProperty("content")]
|
[JsonProperty("content")]
|
||||||
internal Optional<string> _content { get; set; }
|
public Optional<string> Content { get; set; }
|
||||||
public string Content { set { _content = value; } }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
11
src/Discord.Net.Core/API/Rest/ModifyPresenceParams.cs
Normal file
11
src/Discord.Net.Core/API/Rest/ModifyPresenceParams.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#pragma warning disable CS1591
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Discord.API.Rest
|
||||||
|
{
|
||||||
|
public class ModifyPresenceParams
|
||||||
|
{
|
||||||
|
public Optional<UserStatus> Status { get; set; }
|
||||||
|
public Optional<Game> Game { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,7 +7,6 @@ namespace Discord.API.Rest
|
|||||||
public class ModifyTextChannelParams : ModifyGuildChannelParams
|
public class ModifyTextChannelParams : ModifyGuildChannelParams
|
||||||
{
|
{
|
||||||
[JsonProperty("topic")]
|
[JsonProperty("topic")]
|
||||||
internal Optional<string> _topic { get; set; }
|
public Optional<string> Topic { get; set; }
|
||||||
public string Topic { set { _topic = value; } }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,11 +7,8 @@ namespace Discord.API.Rest
|
|||||||
public class ModifyVoiceChannelParams : ModifyGuildChannelParams
|
public class ModifyVoiceChannelParams : ModifyGuildChannelParams
|
||||||
{
|
{
|
||||||
[JsonProperty("bitrate")]
|
[JsonProperty("bitrate")]
|
||||||
internal Optional<int> _bitrate { get; set; }
|
public Optional<int> Bitrate { get; set; }
|
||||||
public int Bitrate { set { _bitrate = value; } }
|
|
||||||
|
|
||||||
[JsonProperty("user_limit")]
|
[JsonProperty("user_limit")]
|
||||||
internal Optional<int> _userLimit { get; set; }
|
public Optional<int> UserLimit { get; set; }
|
||||||
public int UserLimit { set { _userLimit = value; } }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
35
src/Discord.Net.Core/API/Rest/UploadFileParams.cs
Normal file
35
src/Discord.Net.Core/API/Rest/UploadFileParams.cs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
#pragma warning disable CS1591
|
||||||
|
using Discord.Net.Rest;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Discord.API.Rest
|
||||||
|
{
|
||||||
|
public class UploadFileParams
|
||||||
|
{
|
||||||
|
public Stream File { get; }
|
||||||
|
|
||||||
|
public Optional<string> Filename { get; set; }
|
||||||
|
public Optional<string> Content { get; set; }
|
||||||
|
public Optional<string> Nonce { get; set; }
|
||||||
|
public Optional<bool> IsTTS { get; set; }
|
||||||
|
|
||||||
|
public UploadFileParams(Stream file)
|
||||||
|
{
|
||||||
|
File = file;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IReadOnlyDictionary<string, object> ToDictionary()
|
||||||
|
{
|
||||||
|
var d = new Dictionary<string, object>();
|
||||||
|
d["file"] = new MultipartFile(File, Filename.GetValueOrDefault("unknown.dat"));
|
||||||
|
if (Content.IsSpecified)
|
||||||
|
d["content"] = Content.Value;
|
||||||
|
if (IsTTS.IsSpecified)
|
||||||
|
d["tts"] = IsTTS.Value.ToString();
|
||||||
|
if (Nonce.IsSpecified)
|
||||||
|
d["nonce"] = Nonce.Value;
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
7
src/Discord.Net.Core/AssemblyInfo.cs
Normal file
7
src/Discord.Net.Core/AssemblyInfo.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
[assembly: InternalsVisibleTo("Discord.Net.Rest")]
|
||||||
|
[assembly: InternalsVisibleTo("Discord.Net.Rpc")]
|
||||||
|
[assembly: InternalsVisibleTo("Discord.Net.WebSocket")]
|
||||||
|
[assembly: InternalsVisibleTo("Discord.Net.Commands")]
|
||||||
|
[assembly: InternalsVisibleTo("Discord.Net.Tests")]
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.IO;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Discord.Audio
|
namespace Discord.Audio
|
||||||
@@ -8,8 +9,7 @@ namespace Discord.Audio
|
|||||||
event Func<Task> Connected;
|
event Func<Task> Connected;
|
||||||
event Func<Exception, Task> Disconnected;
|
event Func<Exception, Task> Disconnected;
|
||||||
event Func<int, int, Task> LatencyUpdated;
|
event Func<int, int, Task> LatencyUpdated;
|
||||||
|
|
||||||
DiscordVoiceAPIClient ApiClient { get; }
|
|
||||||
/// <summary> Gets the current connection state of this client. </summary>
|
/// <summary> Gets the current connection state of this client. </summary>
|
||||||
ConnectionState ConnectionState { get; }
|
ConnectionState ConnectionState { get; }
|
||||||
/// <summary> Gets the estimated round-trip latency, in milliseconds, to the gateway server. </summary>
|
/// <summary> Gets the estimated round-trip latency, in milliseconds, to the gateway server. </summary>
|
||||||
@@ -17,7 +17,7 @@ namespace Discord.Audio
|
|||||||
|
|
||||||
Task DisconnectAsync();
|
Task DisconnectAsync();
|
||||||
|
|
||||||
RTPWriteStream CreateOpusStream(int samplesPerFrame, int bufferSize = 4000);
|
Stream CreateOpusStream(int samplesPerFrame, int bufferSize = 4000);
|
||||||
OpusEncodeStream CreatePCMStream(int samplesPerFrame, int? bitrate = null, OpusApplication application = OpusApplication.MusicOrMixed, int bufferSize = 4000);
|
Stream CreatePCMStream(int samplesPerFrame, int? bitrate = null, OpusApplication application = OpusApplication.MusicOrMixed, int bufferSize = 4000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
19
src/Discord.Net.Core/Discord.Net.Core.xproj
Normal file
19
src/Discord.Net.Core/Discord.Net.Core.xproj
Normal 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>
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user