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