| @@ -19,6 +19,10 @@ Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Discord.Net.Utils", "src\Di | |||||
| EndProject | EndProject | ||||
| Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Discord.Net.Rest", "src\Discord.Net.Rest\Discord.Net.Rest.xproj", "{BFC6DC28-0351-4573-926A-D4124244C04F}" | Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Discord.Net.Rest", "src\Discord.Net.Rest\Discord.Net.Rest.xproj", "{BFC6DC28-0351-4573-926A-D4124244C04F}" | ||||
| EndProject | 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 | |||||
| Global | Global | ||||
| GlobalSection(SharedMSBuildProjectFiles) = preSolution | GlobalSection(SharedMSBuildProjectFiles) = preSolution | ||||
| src\Discord.Net.Utils\Discord.Net.Utils.projitems*{2b75119c-9893-4aaa-8d38-6176eeb09060}*SharedItemsImports = 13 | src\Discord.Net.Utils\Discord.Net.Utils.projitems*{2b75119c-9893-4aaa-8d38-6176eeb09060}*SharedItemsImports = 13 | ||||
| @@ -40,11 +44,21 @@ Global | |||||
| {BFC6DC28-0351-4573-926A-D4124244C04F}.Debug|Any CPU.Build.0 = 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.ActiveCfg = Release|Any CPU | ||||
| {BFC6DC28-0351-4573-926A-D4124244C04F}.Release|Any CPU.Build.0 = 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 | |||||
| EndGlobalSection | EndGlobalSection | ||||
| GlobalSection(SolutionProperties) = preSolution | GlobalSection(SolutionProperties) = preSolution | ||||
| HideSolutionNode = FALSE | HideSolutionNode = FALSE | ||||
| EndGlobalSection | EndGlobalSection | ||||
| GlobalSection(NestedProjects) = preSolution | GlobalSection(NestedProjects) = preSolution | ||||
| {BFC6DC28-0351-4573-926A-D4124244C04F} = {288C363D-A636-4EAE-9AC1-4698B641B26E} | {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 | EndGlobalSection | ||||
| EndGlobal | EndGlobal | ||||
| @@ -0,0 +1,15 @@ | |||||
| # Contributing to Docs | |||||
| I don't really have any strict conditions for writing documentation, but just keep these few guidelines in mind: | |||||
| * Keep code samples in the `guides/samples` folder | |||||
| * When referencing an object in the API, link to it's page in the API documentation. | |||||
| * Documentation should be written in clear and proper English* | |||||
| \* If anyone is interested in translating documentation into other languages, please open an issue or contact me on Discord (`foxbot#0282`). | |||||
| ### Compiling | |||||
| Documentation is compiled into a static site using [DocFx](dotnet.github.io/docfx/). You **must** install a version of DocFx that supports .NET Core. The latest build of that is [2.1.0-cli-alpha](https://github.com/dotnet/docfx/releases/tag/v2.1.0-cli-alpha). | |||||
| After making changes, compile your changes into the static site with `docfx`. You can also view your changes live with `docfx --serve`. | |||||
| @@ -6,9 +6,9 @@ using Discord.WebSocket; | |||||
| public class Info | public class Info | ||||
| { | { | ||||
| // ~say hello -> hello | // ~say hello -> hello | ||||
| [Command("say"), Description("Echos a message.")] | |||||
| [Command("say"), Summary("Echos a message.")] | |||||
| public async Task Say(IUserMessage msg, | public async Task Say(IUserMessage msg, | ||||
| [Unparsed, Description("The text to echo")] string echo) | |||||
| [Unparsed, Summary("The text to echo")] string echo) | |||||
| { | { | ||||
| await msg.Channel.SendMessageAsync(echo); | await msg.Channel.SendMessageAsync(echo); | ||||
| } | } | ||||
| @@ -19,9 +19,9 @@ public class Info | |||||
| public class Sample | public class Sample | ||||
| { | { | ||||
| // ~sample square 20 -> | // ~sample square 20 -> | ||||
| [Command("square"), Description("Squares a number.")] | |||||
| [Command("square"), Summary("Squares a number.")] | |||||
| public async Task Square(IUserMessage msg, | public async Task Square(IUserMessage msg, | ||||
| [Description("The number to square.")] int num) | |||||
| [Summary("The number to square.")] int num) | |||||
| { | { | ||||
| await msg.Channel.SendMessageAsync($"{num}^2 = {Math.Pow(num, 2)}"); | await msg.Channel.SendMessageAsync($"{num}^2 = {Math.Pow(num, 2)}"); | ||||
| } | } | ||||
| @@ -32,10 +32,10 @@ public class Sample | |||||
| // ~sample userinfo Khionu --> Khionu#8708 | // ~sample userinfo Khionu --> Khionu#8708 | ||||
| // ~sample userinfo 96642168176807936 --> Khionu#8708 | // ~sample userinfo 96642168176807936 --> Khionu#8708 | ||||
| // ~sample whois 96642168176807936 --> Khionu#8708 | // ~sample whois 96642168176807936 --> Khionu#8708 | ||||
| [Command("userinfo"), Description("Returns info about the current user, or the user parameter, if one passed.")] | |||||
| [Command("userinfo"), Summary("Returns info about the current user, or the user parameter, if one passed.")] | |||||
| [Alias("user", "whois")] | [Alias("user", "whois")] | ||||
| public async Task UserInfo(IUserMessage msg, | public async Task UserInfo(IUserMessage msg, | ||||
| [Description("The (optional) user to get info for")] IUser user = null) | |||||
| [Summary("The (optional) user to get info for")] IUser user = null) | |||||
| { | { | ||||
| var userInfo = user ?? await Program.Client.GetCurrentUserAsync(); | var userInfo = user ?? await Program.Client.GetCurrentUserAsync(); | ||||
| await msg.Channel.SendMessageAsync($"{userInfo.Username}#{userInfo.Discriminator}"); | await msg.Channel.SendMessageAsync($"{userInfo.Username}#{userInfo.Discriminator}"); | ||||
| @@ -1,6 +1,6 @@ | |||||
| # Migrating from 0.9 | # Migrating from 0.9 | ||||
| **1.0.0 is the biggest breaking change the library has gone through, do to massive | |||||
| **1.0.0 is the biggest breaking change the library has gone through, due to massive | |||||
| changes in the design of the library.** | changes in the design of the library.** | ||||
| >A medium to advanced understanding is recommended when working with this library. | >A medium to advanced understanding is recommended when working with this library. | ||||
| @@ -78,4 +78,4 @@ provide java-esque, synchronus `GetXXX` methods to replace the asynchronus metho | |||||
| This functionality may be changed at a later date, we are currently reviewing this implementation and | This functionality may be changed at a later date, we are currently reviewing this implementation and | ||||
| alternative methods. | alternative methods. | ||||
| For your reference, you may want to look through the extension classes located in @Discord.WebSocket | |||||
| For your reference, you may want to look through the extension classes located in @Discord.WebSocket | |||||
| @@ -0,0 +1,18 @@ | |||||
| using System; | |||||
| namespace Discord.Commands | |||||
| { | |||||
| /// <summary> Sets priority of commands </summary> | |||||
| [AttributeUsage(AttributeTargets.Method)] | |||||
| public class PriorityAttribute : Attribute | |||||
| { | |||||
| /// <summary> The priority which has been set for the command </summary> | |||||
| public int Priority { get; } | |||||
| /// <summary> Creates a new <see cref="PriorityAttribute"/> with the given priority. </summary> | |||||
| public PriorityAttribute(int priority) | |||||
| { | |||||
| Priority = priority; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -2,13 +2,13 @@ | |||||
| namespace Discord.Commands | namespace Discord.Commands | ||||
| { | { | ||||
| // Full summary of method | |||||
| // Extension of the Cosmetic Summary, for Groups, Commands, and Parameters | |||||
| [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] | [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] | ||||
| public class DescriptionAttribute : Attribute | |||||
| public class RemarksAttribute : Attribute | |||||
| { | { | ||||
| public string Text { get; } | public string Text { get; } | ||||
| public DescriptionAttribute(string text) | |||||
| public RemarksAttribute(string text) | |||||
| { | { | ||||
| Text = text; | Text = text; | ||||
| } | } | ||||
| @@ -2,7 +2,7 @@ | |||||
| namespace Discord.Commands | namespace Discord.Commands | ||||
| { | { | ||||
| // Brief summary of method/module/parameter | |||||
| // Cosmetic Summary, for Groups and Commands | |||||
| [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Parameter)] | [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Parameter)] | ||||
| public class SummaryAttribute : Attribute | public class SummaryAttribute : Attribute | ||||
| { | { | ||||
| @@ -21,9 +21,10 @@ namespace Discord.Commands | |||||
| public MethodInfo Source { get; } | public MethodInfo Source { get; } | ||||
| public Module Module { get; } | public Module Module { get; } | ||||
| public string Name { get; } | public string Name { get; } | ||||
| public string Description { get; } | |||||
| public string Summary { get; } | public string Summary { get; } | ||||
| public string Remarks { get; } | |||||
| public string Text { get; } | public string Text { get; } | ||||
| public int Priority { get; } | |||||
| public bool HasVarArgs { get; } | public bool HasVarArgs { get; } | ||||
| public IReadOnlyList<string> Aliases { get; } | public IReadOnlyList<string> Aliases { get; } | ||||
| public IReadOnlyList<CommandParameter> Parameters { get; } | public IReadOnlyList<CommandParameter> Parameters { get; } | ||||
| @@ -38,7 +39,15 @@ namespace Discord.Commands | |||||
| _instance = instance; | _instance = instance; | ||||
| Name = source.Name; | Name = source.Name; | ||||
| Text = groupPrefix + attribute.Text; | |||||
| if (attribute.Text == null) | |||||
| Text = groupPrefix; | |||||
| if (groupPrefix != "") | |||||
| groupPrefix += " "; | |||||
| if (attribute.Text != null) | |||||
| Text = groupPrefix + attribute.Text; | |||||
| var aliasesBuilder = ImmutableArray.CreateBuilder<string>(); | var aliasesBuilder = ImmutableArray.CreateBuilder<string>(); | ||||
| @@ -54,14 +63,17 @@ namespace Discord.Commands | |||||
| if (nameAttr != null) | if (nameAttr != null) | ||||
| Name = nameAttr.Text; | Name = nameAttr.Text; | ||||
| var description = source.GetCustomAttribute<DescriptionAttribute>(); | |||||
| if (description != null) | |||||
| Description = description.Text; | |||||
| var summary = source.GetCustomAttribute<SummaryAttribute>(); | var summary = source.GetCustomAttribute<SummaryAttribute>(); | ||||
| if (summary != null) | if (summary != null) | ||||
| Summary = summary.Text; | Summary = summary.Text; | ||||
| var remarksAttr = source.GetCustomAttribute<RemarksAttribute>(); | |||||
| if (remarksAttr != null) | |||||
| Remarks = remarksAttr.Text; | |||||
| var priorityAttr = source.GetCustomAttribute<PriorityAttribute>(); | |||||
| Priority = priorityAttr?.Priority ?? 0; | |||||
| Parameters = BuildParameters(source); | Parameters = BuildParameters(source); | ||||
| HasVarArgs = Parameters.Count > 0 ? Parameters[Parameters.Count - 1].IsMultiple : false; | HasVarArgs = Parameters.Count > 0 ? Parameters[Parameters.Count - 1].IsMultiple : false; | ||||
| Preconditions = BuildPreconditions(source); | Preconditions = BuildPreconditions(source); | ||||
| @@ -150,6 +150,8 @@ namespace Discord.Commands | |||||
| for (int i = argList.Count; i < command.Parameters.Count; i++) | for (int i = argList.Count; i < command.Parameters.Count; i++) | ||||
| { | { | ||||
| var param = command.Parameters[i]; | var param = command.Parameters[i]; | ||||
| if (param.IsMultiple) | |||||
| continue; | |||||
| if (!param.IsOptional) | if (!param.IsOptional) | ||||
| return ParseResult.FromError(CommandError.BadArgCount, "The input text has too few parameters."); | return ParseResult.FromError(CommandError.BadArgCount, "The input text has too few parameters."); | ||||
| argList.Add(TypeReaderResult.FromSuccess(param.DefaultValue)); | argList.Add(TypeReaderResult.FromSuccess(param.DefaultValue)); | ||||
| @@ -180,7 +180,7 @@ namespace Discord.Commands | |||||
| public SearchResult Search(IUserMessage message, string input) | public SearchResult Search(IUserMessage message, string input) | ||||
| { | { | ||||
| string lowerInput = input.ToLowerInvariant(); | string lowerInput = input.ToLowerInvariant(); | ||||
| var matches = _map.GetCommands(input).ToImmutableArray(); | |||||
| var matches = _map.GetCommands(input).OrderByDescending(x => x.Priority).ToImmutableArray(); | |||||
| if (matches.Length > 0) | if (matches.Length > 0) | ||||
| return SearchResult.FromSuccess(input, matches); | return SearchResult.FromSuccess(input, matches); | ||||
| @@ -7,6 +7,7 @@ namespace Discord.Commands | |||||
| internal class CommandMap | internal class CommandMap | ||||
| { | { | ||||
| static readonly char[] _whitespaceChars = new char[] { ' ', '\r', '\n' }; | static readonly char[] _whitespaceChars = new char[] { ' ', '\r', '\n' }; | ||||
| private readonly object _lockObj = new object(); | |||||
| private readonly ConcurrentDictionary<string, CommandMapNode> _nodes; | private readonly ConcurrentDictionary<string, CommandMapNode> _nodes; | ||||
| @@ -23,11 +24,11 @@ namespace Discord.Commands | |||||
| string name; | string name; | ||||
| if (nextSpace == -1) | if (nextSpace == -1) | ||||
| name = command.Text; | |||||
| name = text; | |||||
| else | else | ||||
| name = command.Text.Substring(0, nextSpace); | |||||
| name = text.Substring(0, nextSpace); | |||||
| lock (this) | |||||
| lock (_lockObj) | |||||
| { | { | ||||
| var nextNode = _nodes.GetOrAdd(name, x => new CommandMapNode(x)); | var nextNode = _nodes.GetOrAdd(name, x => new CommandMapNode(x)); | ||||
| nextNode.AddCommand(nextSpace == -1 ? "" : text, nextSpace + 1, command); | nextNode.AddCommand(nextSpace == -1 ? "" : text, nextSpace + 1, command); | ||||
| @@ -42,11 +43,11 @@ namespace Discord.Commands | |||||
| string name; | string name; | ||||
| if (nextSpace == -1) | if (nextSpace == -1) | ||||
| name = command.Text; | |||||
| name = text; | |||||
| else | else | ||||
| name = command.Text.Substring(0, nextSpace); | |||||
| name = text.Substring(0, nextSpace); | |||||
| lock (this) | |||||
| lock (_lockObj) | |||||
| { | { | ||||
| CommandMapNode nextNode; | CommandMapNode nextNode; | ||||
| if (_nodes.TryGetValue(name, out nextNode)) | if (_nodes.TryGetValue(name, out nextNode)) | ||||
| @@ -69,7 +70,7 @@ namespace Discord.Commands | |||||
| else | else | ||||
| name = text.Substring(0, nextSpace); | name = text.Substring(0, nextSpace); | ||||
| lock (this) | |||||
| lock (_lockObj) | |||||
| { | { | ||||
| CommandMapNode nextNode; | CommandMapNode nextNode; | ||||
| if (_nodes.TryGetValue(name, out nextNode)) | if (_nodes.TryGetValue(name, out nextNode)) | ||||
| @@ -8,6 +8,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 ImmutableArray<Command> _commands; | private ImmutableArray<Command> _commands; | ||||
| public bool IsEmpty => _commands.Length == 0 && _nodes.Count == 0; | public bool IsEmpty => _commands.Length == 0 && _nodes.Count == 0; | ||||
| @@ -24,7 +25,7 @@ namespace Discord.Commands | |||||
| int nextSpace = text.IndexOf(' ', index); | int nextSpace = text.IndexOf(' ', index); | ||||
| string name; | string name; | ||||
| lock (this) | |||||
| lock (_lockObj) | |||||
| { | { | ||||
| if (text == "") | if (text == "") | ||||
| _commands = _commands.Add(command); | _commands = _commands.Add(command); | ||||
| @@ -45,7 +46,7 @@ namespace Discord.Commands | |||||
| int nextSpace = text.IndexOf(' ', index); | int nextSpace = text.IndexOf(' ', index); | ||||
| string name; | string name; | ||||
| lock (this) | |||||
| lock (_lockObj) | |||||
| { | { | ||||
| if (text == "") | if (text == "") | ||||
| _commands = _commands.Remove(command); | _commands = _commands.Remove(command); | ||||
| @@ -13,7 +13,7 @@ namespace Discord.Commands | |||||
| 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 Description { get; } | |||||
| public string Remarks { get; } | |||||
| public IEnumerable<Command> Commands { get; } | public IEnumerable<Command> Commands { get; } | ||||
| internal object Instance { get; } | internal object Instance { get; } | ||||
| @@ -35,9 +35,9 @@ namespace Discord.Commands | |||||
| if (summaryAttr != null) | if (summaryAttr != null) | ||||
| Summary = summaryAttr.Text; | Summary = summaryAttr.Text; | ||||
| var descriptionAttr = source.GetCustomAttribute<DescriptionAttribute>(); | |||||
| if (descriptionAttr != null) | |||||
| Description = descriptionAttr.Text; | |||||
| var remarksAttr = source.GetCustomAttribute<RemarksAttribute>(); | |||||
| if (remarksAttr != null) | |||||
| Remarks = remarksAttr.Text; | |||||
| List<Command> commands = new List<Command>(); | List<Command> commands = new List<Command>(); | ||||
| SearchClass(source, instance, commands, Prefix, dependencyMap); | SearchClass(source, instance, commands, Prefix, dependencyMap); | ||||
| @@ -48,8 +48,6 @@ namespace Discord.Commands | |||||
| private void SearchClass(TypeInfo parentType, object instance, List<Command> commands, string groupPrefix, IDependencyMap dependencyMap) | private void SearchClass(TypeInfo parentType, object instance, List<Command> commands, string groupPrefix, IDependencyMap dependencyMap) | ||||
| { | { | ||||
| if (groupPrefix != "") | |||||
| groupPrefix += " "; | |||||
| foreach (var method in parentType.DeclaredMethods) | foreach (var method in parentType.DeclaredMethods) | ||||
| { | { | ||||
| var cmdAttr = method.GetCustomAttribute<CommandAttribute>(); | var cmdAttr = method.GetCustomAttribute<CommandAttribute>(); | ||||
| @@ -62,10 +60,12 @@ namespace Discord.Commands | |||||
| if (groupAttrib != null) | if (groupAttrib != null) | ||||
| { | { | ||||
| string nextGroupPrefix; | string nextGroupPrefix; | ||||
| if (groupAttrib.Prefix != null) | |||||
| nextGroupPrefix = groupPrefix + groupAttrib.Prefix ?? type.Name; | |||||
| if (groupPrefix != "") | |||||
| nextGroupPrefix = groupPrefix + " " + (groupAttrib.Prefix ?? type.Name.ToLowerInvariant()); | |||||
| else | else | ||||
| nextGroupPrefix = groupPrefix; | |||||
| nextGroupPrefix = groupAttrib.Prefix ?? type.Name.ToLowerInvariant(); | |||||
| SearchClass(type, ReflectionUtils.CreateObject(type, Service, dependencyMap), commands, nextGroupPrefix, dependencyMap); | SearchClass(type, ReflectionUtils.CreateObject(type, Service, dependencyMap), commands, nextGroupPrefix, dependencyMap); | ||||
| } | } | ||||
| } | } | ||||
| @@ -2,6 +2,9 @@ | |||||
| { | { | ||||
| public static class Format | public static class Format | ||||
| { | { | ||||
| // Characters which need escaping | |||||
| private static string[] SensitiveCharacters = { "*", "_", "~", "`", "\\" }; | |||||
| /// <summary> Returns a markdown-formatted string with bold formatting. </summary> | /// <summary> Returns a markdown-formatted string with bold formatting. </summary> | ||||
| public static string Bold(string text) => $"**{text}**"; | public static string Bold(string text) => $"**{text}**"; | ||||
| /// <summary> Returns a markdown-formatted string with italics formatting. </summary> | /// <summary> Returns a markdown-formatted string with italics formatting. </summary> | ||||
| @@ -19,5 +22,15 @@ | |||||
| else | else | ||||
| return $"`{text}`"; | return $"`{text}`"; | ||||
| } | } | ||||
| /// <summary> Sanitizes the string, safely escaping any Markdown sequences. </summary> | |||||
| public static string Sanitize(string text) | |||||
| { | |||||
| foreach (string unsafeChar in SensitiveCharacters) | |||||
| { | |||||
| text = text.Replace(unsafeChar, $"\\{unsafeChar}"); | |||||
| } | |||||
| return text; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -38,7 +38,7 @@ namespace Discord.WebSocket | |||||
| private int _nextAudioId; | private int _nextAudioId; | ||||
| private bool _canReconnect; | private bool _canReconnect; | ||||
| /// <summary> Gets the shard if of this client. </summary> | |||||
| /// <summary> Gets the shard of of this client. </summary> | |||||
| public int ShardId { get; } | public int ShardId { get; } | ||||
| /// <summary> Gets the current connection state of this client. </summary> | /// <summary> Gets the current connection state of this client. </summary> | ||||
| public ConnectionState ConnectionState { get; private set; } | public ConnectionState ConnectionState { get; private set; } | ||||
| @@ -793,6 +793,7 @@ namespace Discord.WebSocket | |||||
| if (guild != null) | if (guild != null) | ||||
| { | { | ||||
| guild.AddChannel(data, DataStore); | guild.AddChannel(data, DataStore); | ||||
| channel = guild.AddChannel(data, DataStore); | |||||
| if (!guild.IsSynced) | if (!guild.IsSynced) | ||||
| { | { | ||||
| @@ -1263,6 +1264,12 @@ namespace Discord.WebSocket | |||||
| } | } | ||||
| if (after != null) | if (after != null) | ||||
| await _messageUpdatedEvent.InvokeAsync(Optional.Create(before), after).ConfigureAwait(false); | await _messageUpdatedEvent.InvokeAsync(Optional.Create(before), after).ConfigureAwait(false); | ||||
| { | |||||
| if (before != null) | |||||
| await _messageUpdatedEvent.InvokeAsync(Optional.Create<IMessage>(before), after).ConfigureAwait(false); | |||||
| else | |||||
| await _messageUpdatedEvent.InvokeAsync(Optional.Create<IMessage>(), after).ConfigureAwait(false); | |||||
| } | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| @@ -148,11 +148,12 @@ namespace Discord.WebSocket | |||||
| public override Task<IGuildChannel> GetChannelAsync(ulong id) => Task.FromResult<IGuildChannel>(GetChannel(id)); | public override Task<IGuildChannel> GetChannelAsync(ulong id) => Task.FromResult<IGuildChannel>(GetChannel(id)); | ||||
| public override Task<IReadOnlyCollection<IGuildChannel>> GetChannelsAsync() => Task.FromResult<IReadOnlyCollection<IGuildChannel>>(Channels); | public override Task<IReadOnlyCollection<IGuildChannel>> GetChannelsAsync() => Task.FromResult<IReadOnlyCollection<IGuildChannel>>(Channels); | ||||
| public void AddChannel(ChannelModel model, DataStore dataStore, ConcurrentHashSet<ulong> channels = null) | |||||
| public ISocketGuildChannel AddChannel(ChannelModel model, DataStore dataStore, ConcurrentHashSet<ulong> channels = null) | |||||
| { | { | ||||
| var channel = ToChannel(model); | var channel = ToChannel(model); | ||||
| (channels ?? _channels).TryAdd(model.Id); | (channels ?? _channels).TryAdd(model.Id); | ||||
| dataStore.AddChannel(channel); | dataStore.AddChannel(channel); | ||||
| return channel; | |||||
| } | } | ||||
| public ISocketGuildChannel GetChannel(ulong id) | public ISocketGuildChannel GetChannel(ulong id) | ||||
| { | { | ||||
| @@ -8,6 +8,7 @@ namespace Discord.WebSocket | |||||
| internal class SocketGlobalUser : User, ISocketUser | internal class SocketGlobalUser : User, ISocketUser | ||||
| { | { | ||||
| internal override bool IsAttached => true; | internal override bool IsAttached => true; | ||||
| private readonly object _lockObj = new object(); | |||||
| private ushort _references; | private ushort _references; | ||||
| @@ -25,13 +26,13 @@ namespace Discord.WebSocket | |||||
| { | { | ||||
| checked | checked | ||||
| { | { | ||||
| lock (this) | |||||
| lock (_lockObj) | |||||
| _references++; | _references++; | ||||
| } | } | ||||
| } | } | ||||
| public void RemoveRef(DiscordSocketClient discord) | public void RemoveRef(DiscordSocketClient discord) | ||||
| { | { | ||||
| lock (this) | |||||
| lock (_lockObj) | |||||
| { | { | ||||
| if (--_references == 0) | if (--_references == 0) | ||||
| discord.RemoveUser(Id); | discord.RemoveUser(Id); | ||||
| @@ -40,16 +41,16 @@ namespace Discord.WebSocket | |||||
| public override void Update(Model model) | public override void Update(Model model) | ||||
| { | { | ||||
| lock (this) | |||||
| lock (_lockObj) | |||||
| base.Update(model, source); | base.Update(model, source); | ||||
| } | } | ||||
| public void Update(PresenceModel model) | public void Update(PresenceModel model) | ||||
| { | { | ||||
| //Race conditions are okay here. Multiple shards racing already cant guarantee presence in order. | //Race conditions are okay here. Multiple shards racing already cant guarantee presence in order. | ||||
| //lock (this) | |||||
| //lock (_lockObj) | |||||
| //{ | //{ | ||||
| var game = model.Game != null ? new Game(model.Game) : null; | |||||
| var game = model.Game != null ? new Game(model.Game) : null; | |||||
| Presence = new Presence(game, model.Status); | Presence = new Presence(game, model.Status); | ||||
| //} | //} | ||||
| } | } | ||||
| @@ -1,11 +1,10 @@ | |||||
| { | { | ||||
| "version": "1.0.0-*", | |||||
| "version": "1.0.0-beta2-*", | |||||
| "buildOptions": { | "buildOptions": { | ||||
| "compile": { | "compile": { | ||||
| "include": [ "../Discord.Net.Entities/**.cs", "../Discord.Net.Utils/**.cs" ] | |||||
| }, | |||||
| "define": [ "WEBSOCKET" ] | |||||
| "include": [ "../Discord.Net.Utils/**.cs" ] | |||||
| } | |||||
| }, | }, | ||||
| "dependencies": { | "dependencies": { | ||||
| @@ -1,6 +1,6 @@ | |||||
| { | |||||
| "version": "1.0.0-beta2-*", | |||||
| "description": "An aynchronous API wrapper for Discord using .NET. This package includes all of the optional Discord.Net components", | |||||
| { | |||||
| "version": "1.0.0-beta-*", | |||||
| "description": "An unofficial .Net API wrapper for the Discord service.", | |||||
| "authors": [ "RogueException" ], | "authors": [ "RogueException" ], | ||||
| "packOptions": { | "packOptions": { | ||||
| @@ -13,19 +13,38 @@ | |||||
| } | } | ||||
| }, | }, | ||||
| "dependencies": { | |||||
| "Discord.Net.Rest": { | |||||
| "target": "project" | |||||
| "buildOptions": { | |||||
| "allowUnsafe": true, | |||||
| "warningsAsErrors": false, | |||||
| "xmlDoc": true | |||||
| }, | |||||
| "configurations": { | |||||
| "Release": { | |||||
| "buildOptions": { | |||||
| "define": [ "RELEASE" ], | |||||
| "nowarn": [ "CS1573", "CS1591" ], | |||||
| "optimize": true | |||||
| } | |||||
| } | } | ||||
| //"Discord.Net.WebSocket": { | |||||
| // "target": "project" | |||||
| //}, | |||||
| //"Discord.Net.Rpc": { | |||||
| // "target": "project" | |||||
| //}, | |||||
| //"Discord.Net.Commands": { | |||||
| // "target": "project" | |||||
| //} | |||||
| }, | |||||
| "dependencies": { | |||||
| "Microsoft.Win32.Primitives": "4.0.1", | |||||
| "Newtonsoft.Json": "8.0.3", | |||||
| "System.Collections.Concurrent": "4.0.12", | |||||
| "System.Collections.Immutable": "1.2.0", | |||||
| "System.IO.Compression": "4.1.0", | |||||
| "System.IO.FileSystem": "4.0.1", | |||||
| "System.Net.Http": "4.1.0", | |||||
| "System.Net.NameResolution": "4.0.0", | |||||
| "System.Net.Sockets": "4.1.0", | |||||
| "System.Net.WebSockets.Client": "4.0.0", | |||||
| "System.Reflection.Extensions": "4.0.1", | |||||
| "System.Runtime.InteropServices": "4.1.0", | |||||
| "System.Runtime.InteropServices.RuntimeInformation": "4.0.0", | |||||
| "System.Runtime.Serialization.Primitives": "4.1.1", | |||||
| "System.Text.RegularExpressions": "4.1.0" | |||||
| }, | }, | ||||
| "frameworks": { | "frameworks": { | ||||