From 77342903bb8a38c30540a25397d7b0de8ccd676c Mon Sep 17 00:00:00 2001 From: Christopher F Date: Sat, 15 Oct 2016 17:28:36 -0400 Subject: [PATCH] Update Documentation to be compatible with Beta2 this one took a while --- docs/api/index.md | 8 +- docs/guides/commands.md | 154 ++++++++++++------ docs/guides/intro.md | 2 + docs/guides/samples.md | 6 +- docs/guides/samples/command_handler.cs | 20 +-- docs/guides/samples/dependency_map_setup.cs | 13 +- docs/guides/samples/faq/avatar.cs | 2 +- docs/guides/samples/faq/guild_from_message.cs | 4 - docs/guides/samples/faq/send_message.cs | 2 +- docs/guides/samples/groups.cs | 10 +- docs/guides/samples/module.cs | 29 ++-- docs/guides/samples/require_context.cs | 7 +- docs/guides/samples/require_owner.cs | 16 +- docs/guides/samples/require_permission.cs | 5 +- docs/guides/samples/typereader.cs | 2 +- docs/guides/terminology.md | 31 +++- docs/migrating.md | 42 ++--- 17 files changed, 206 insertions(+), 147 deletions(-) delete mode 100644 docs/guides/samples/faq/guild_from_message.cs diff --git a/docs/api/index.md b/docs/api/index.md index 3028eef57..87b455a2f 100644 --- a/docs/api/index.md +++ b/docs/api/index.md @@ -3,4 +3,10 @@ This is where you will find documentation for all members and objects in Discord.Net -**TODO:** Think of something useful to put on this page. \ No newline at end of file +__Commonly Used Entities__ +@Discord.WebSocket +@Discord.WebSocket.DiscordSocketClient +@Discord.WebSocket.SocketGuildChannel +@Discord.WebSocket.SocketGuildUser +@Discord.WebSocket.SocketMessage +@Discord.WebSocket.SocketRole \ No newline at end of file diff --git a/docs/guides/commands.md b/docs/guides/commands.md index ef2a15f85..eea89496d 100644 --- a/docs/guides/commands.md +++ b/docs/guides/commands.md @@ -1,37 +1,60 @@ # The Command Service -[Discord.Commands](xref:Discord.Commands) provides an Attribute-based Command Parser. +[Discord.Commands](xref:Discord.Commands) provides an Attribute-based + Command Parser. ### Setup -To use Commands, you must create a [Commands Service](xref:Discord.Commands.CommandService) and a Command Handler. +To use Commands, you must create a +[Commands Service](xref:Discord.Commands.CommandService) +and a Command Handler. -Included below is a very bare-bones Command Handler. You can extend your Command Handler as much as you like, however the below is the bare minimum. +Included below is a very bare-bones Command Handler. You can extend +your Command Handler as much as you like, however the below is the +bare minimum. [!code-csharp[Barebones Command Handler](samples/command_handler.cs)] ## Commands -In 1.0, Commands are no longer implemented at runtime with a builder pattern. -While a builder pattern may be provided later, commands are created primarily with -attributes. +In 1.0, Commands are no longer implemented at runtime with a builder +pattern. While a builder pattern may be provided later, commands are +created primarily with attributes. ### Basic Structure -All commands belong to a Module. (See the below section for creating modules.) +All commands belong to a Module. (See the below section for creating +modules). -All commands in a module must be defined as an `Task`, with at least one argument, -being the @Discord.IUserMessage representing the context of the command. +All commands in a module must be defined as a `Task`. -To add parameters to your command, add additional arguments to the `Task` of the command. -You are _not_ required to accept all arguments as `String`, they will be automatically parsed -into the type you specify for the arument. See the Example Module for an example of command parameters. +To add parameters to your command, you simply need to add parameters +to the Task that represents the command. You are _not_ required to +accept all arguments as `String`, they will be automatically parsed +into the type you specify for the arument. See the Example Module +for an example of command parameters. ## Modules -Modules serve as a host for commands you create. +Modules are an organizational pattern that allow you to write your +commands in different classes, and have them automatically loaded. -To create a module, create a class that you will place commands in. Flag this class with the `[Module]` attribute. You may optionally pass in a string to the `Module` attribute to set a prefix for all of the commands inside the module. +Discord.Net's implementation of Modules is influenced heavily from +ASP.Net Core's Controller pattern. This means that the lifetime of a +module instance is only as long as the command being ran in it. + +**Avoid using long-running code** in your modules whereever possible. +You should **not** be implementing very much logic into your modules; +outsource to a service for that. + +If you are unfamiliar with Inversion of Control, it is recommended to +read the MSDN article on [IoC] and [Dependency Injection]. + +To create a module, create a class that inherits from +@Discord.Commands.ModuleBase. + +[IoC]: https://msdn.microsoft.com/en-us/library/ff921087.aspx +[Dependency Injection]: https://msdn.microsoft.com/en-us/library/ff921152.aspx ### Example Module @@ -39,68 +62,95 @@ To create a module, create a class that you will place commands in. Flag this cl #### Loading Modules Automatically -The Command Service can automatically discover all classes in an Assembly that are flagged with the `Module` attribute, and load them. +The Command Service can automatically discover all classes in an +Assembly that inherit @Discord.Commands.ModuleBase, and load them. -To have a module opt-out of auto-loading, pass `autoload: false` in the Module attribute. +To have a module opt-out of auto-loading, pass `autoload: false` in +the Module attribute. -Invoke [CommandService.LoadAssembly](xref:Discord.Commands.CommandService#Discord_Commands_CommandService_LoadAssembly) to discover modules and install them. +Invoke [CommandService.AddModules] to discover modules and install them. + +[CommandService.AddModules]: xref:Discord.Commands.CommandService#Discord_Commands_CommandService_AddModules #### Loading Modules Manually -To manually load a module, invoke [CommandService.Load](xref:Discord.Commands.CommandService#Discord_Commands_CommandService_Load), and pass in an instance of your module. +To manually load a module, invoke [CommandService.AddModule], +by passing in the generic type of your module, and optionally +a dependency map. -### Module Constructors +[CommandService.AddModule]: xref:Discord.Commands.CommandService#Discord_Commands_CommandService_AddModule__1_Discord_Commands_IDependencyMap_ -When automatically loading modules, you are limited in your constructor. Using a constructor that accepts _no arguments_, or a constructor that accepts a @Discord.Commands.CommandService will always work. +### Module Constructors -Alternatively, you can use an @Discord.Commands.IDependencyMap, as shown below. +Modules are constructed using Dependency Injection. Any parameters +that are placed in the constructor must be injected into an +@Discord.Commands.IDependencyMap. Alternatively, you may accept an +IDependencyMap as an argument and extract services yourself. ### Command Groups -Command groups function similarly to Modules, but they must be contained inside a module. Simply create a **public** class inside a module, and flag it with the @Discord.Commands.GroupAttribute +Command Groups allow you to create a module where commands are prefixed. +To create a group, create a new module and flag it with the +@Discord.Commands.GroupAttribute. + +>![NOTE] +>Groups do not _need_ to be modules. Only classes with commands should +>inherit from ModuleBase. If you plan on using a group for strictly +>organizational purposes, there is no reason to make it a module. [!code-csharp[Groups Sample](samples/groups.cs)] ## Dependency Injection -The Commands Service includes a very basic implementation of Dependency Injection that allows you to have completely custom constructors, within certain limitations. +The commands service is bundled with a very barebones Dependency +Injection service for your convienence. It is recommended that +you use DI when writing your modules. ### Setup -First, you need to create an @Discord.Commands.IDependencyMap . The library includes @Discord.Commands.DependencyMap to help with this, however you may create your own IDependencyMap if you wish. +First, you need to create an @Discord.Commands.IDependencyMap. +The library includes @Discord.Commands.DependencyMap to help with +this, however you may create your own IDependencyMap if you wish. Next, add the dependencies your modules will use to the map. -Finally, pass the map into the `LoadAssembly` method. Your modules will automatically be loaded with this dependency map. +Finally, pass the map into the `LoadAssembly` method. +Your modules will automatically be loaded with this dependency map. [!code-csharp[DependencyMap Setup](samples/dependency_map_setup.cs)] ### Usage in Modules -In the constructor of your module, any parameters will be filled in by the @Discord.Commands.IDependencyMap you pass into `LoadAssembly`. +In the constructor of your module, any parameters will be filled in by +the @Discord.Commands.IDependencyMap you pass into `LoadAssembly`. >[!NOTE] ->If you accept `CommandService` or `IDependencyMap` as a parameter in your constructor, these parameters will be filled by the CommandService the module was loaded from, and the DependencyMap passed into it, respectively. +>If you accept `CommandService` or `IDependencyMap` as a parameter in +your constructor, these parameters will be filled by the +CommandService the module was loaded from, and the DependencyMap passed +into it, respectively. [!code-csharp[DependencyMap in Modules](samples/dependency_module.cs)] # Preconditions -Preconditions serve as a permissions system for your commands. Keep in mind, however, that they are -not limited to _just_ permissions, and can be as complex as you want them to be. +Preconditions serve as a permissions system for your commands. Keep in +mind, however, that they are not limited to _just_ permissions, and +can be as complex as you want them to be. >[!NOTE] >Preconditions can be applied to Modules, Groups, or Commands. ## Bundled Preconditions -@Discord.Commands ships with two built-in preconditions, @Discord.Commands.RequireContextAttribute -and @Discord.Commands.RequirePermissionAttribute. +@Discord.Commands ships with two built-in preconditions, +@Discord.Commands.RequireContextAttribute and +@Discord.Commands.RequirePermissionAttribute. ### RequireContext -@Discord.Commands.RequireContextAttribute is a precondition that requires your command to be -executed in the specified context. +@Discord.Commands.RequireContextAttribute is a precondition that +requires your command to be executed in the specified context. You may require three different types of context: * Guild @@ -113,29 +163,34 @@ Since these are `Flags`, you may OR them together. ### RequirePermission -@Discord.Commands.RequirePermissionAttribute is a precondition that allows you to quickly -specfiy that a user must poesess a permission to execute a command. +@Discord.Commands.RequirePermissionAttribute is a precondition that +allows you to quickly specfiy that a user must poesess a permission +to execute a command. -You may require either a @Discord.GuildPermission or @Discord.ChannelPermission +You may require either a @Discord.GuildPermission or +@Discord.ChannelPermission [!code-csharp[RequireContext](samples/require_permission.cs)] ## Custom Preconditions -To write your own preconditions, create a new class that inherits from @Discord.Commands.PreconditionAttribute +To write your own preconditions, create a new class that inherits from + @Discord.Commands.PreconditionAttribute -In order for your precondition to function, you will need to override `CheckPermissions`, -which is a `Task`. +In order for your precondition to function, you will need to override +`CheckPermissions`, which is a `Task`. Your IDE should provide an option to fill this in for you. -Return `PreconditionResult.FromSuccess()` if the context met the required parameters, otherwise -return `PreconditionResult.FromError()`, optionally including an error message. +Return `PreconditionResult.FromSuccess()` if the context met the +required parameters, otherwise return `PreconditionResult.FromError()`, +optionally including an error message. [!code-csharp[Custom Precondition](samples/require_owner.cs)] # Type Readers -Type Readers allow you to parse different types of arguments in your commands. +Type Readers allow you to parse different types of arguments in +your commands. By default, the following Types are supported arguments: @@ -153,16 +208,20 @@ By default, the following Types are supported arguments: ### Creating a Type Readers -To create a TypeReader, create a new class that imports @Discord and @Discord.Commands . Ensure your class inherits from @Discord.Commands.TypeReader +To create a TypeReader, create a new class that imports @Discord and +@Discord.Commands. Ensure your class inherits from @Discord.Commands.TypeReader -Next, satisfy the `TypeReader` class by overriding `Task Read(IUserMessage context, string input)`. +Next, satisfy the `TypeReader` class by overriding `Task Read(CommandContext context, string input)`. >[!NOTE] ->In many cases, Visual Studio can fill this in for you, using the "Implement Abstract Class" IntelliSense hint. +>In many cases, Visual Studio can fill this in for you, using the +>"Implement Abstract Class" IntelliSense hint. Inside this task, add whatever logic you need to parse the input string. -Finally, return a `TypeReaderResult`. If you were able to successfully parse the input, return `TypeReaderResult.FromSuccess(parsedInput)`. Otherwise, return `TypeReaderResult.FromError`. +Finally, return a `TypeReaderResult`. If you were able to successfully +parse the input, return `TypeReaderResult.FromSuccess(parsedInput)`. +Otherwise, return `TypeReaderResult.FromError`. #### Sample @@ -170,4 +229,5 @@ Finally, return a `TypeReaderResult`. If you were able to successfully parse the ### Installing TypeReaders -TypeReaders are not automatically discovered by the Command Service, and must be explicitly added. To install a TypeReader, invoke [CommandService.AddTypeReader](xref:Discord.Commands.CommandService#Discord_Commands_CommandService_AddTypeReader__1_Discord_Commands_TypeReader_). \ No newline at end of file +TypeReaders are not automatically discovered by the Command Service, +and must be explicitly added. To install a TypeReader, invoke [CommandService.AddTypeReader](xref:Discord.Commands.CommandService#Discord_Commands_CommandService_AddTypeReader__1_Discord_Commands_TypeReader_). \ No newline at end of file diff --git a/docs/guides/intro.md b/docs/guides/intro.md index e9745a4d8..d02affe3d 100644 --- a/docs/guides/intro.md +++ b/docs/guides/intro.md @@ -16,6 +16,8 @@ Bot accounts must be added to a server, you must use the [OAuth 2 Flow](https:// You can install Discord.Net 1.0 from our [MyGet Feed](https://www.myget.org/feed/Packages/discord-net). +**For most users writing bots, install only `Discord.Net.WebSocket`.** + You may add the MyGet feed to Visual Studio directly from `https://www.myget.org/F/discord-net/api/v3/index.json`. You can also pull the latest source from [GitHub](https://github.com/RogueException/Discord.Net). diff --git a/docs/guides/samples.md b/docs/guides/samples.md index dd0d7164e..ef85e4898 100644 --- a/docs/guides/samples.md +++ b/docs/guides/samples.md @@ -17,8 +17,4 @@ title: Samples #### Sending a message to a channel -[!code-csharp[Message to Channel](samples/faq/send_message.cs)] - -#### Retrieving an IGuild from an IUserMessage - -[!code-csharp[Message to Guild](samples/faq/guild_from_message.cs)] \ No newline at end of file +[!code-csharp[Message to Channel](samples/faq/send_message.cs)] \ No newline at end of file diff --git a/docs/guides/samples/command_handler.cs b/docs/guides/samples/command_handler.cs index 020470427..3ef3bfc6e 100644 --- a/docs/guides/samples/command_handler.cs +++ b/docs/guides/samples/command_handler.cs @@ -33,21 +33,21 @@ public class Program // Discover all of the commands in this assembly and load them. await commands.LoadAssembly(Assembly.GetEntryAssembly()); } - public async Task HandleCommand(IMessage paramMessage) + public async Task HandleCommand(SocketMessage messageParam) { - // Cast paramMessage to an IUserMessage, return if the message was a System message. - var msg = paramMessage as IUserMessage; - if (msg == null) return; - // Internal integer, marks where the command begins + // Don't process the command if it was a System Message + var message = messageParam as SocketUserMessage; + if (message == null) return; + // Create a number to track where the prefix ends and the command begins int argPos = 0; - // Get the current user (used for Mention parsing) - var currentUser = await client.GetCurrentUserAsync(); // Determine if the message is a command, based on if it starts with '!' or a mention prefix - if (msg.HasCharPrefix('!', ref argPos) || msg.HasMentionPrefix(currentUser, ref argPos)) + if (message.HasCharPrefix('!', ref argPos) || message.HasMentionPrefix(client.CurrentUser, ref argPos)) { - // Execute the command. (result does not indicate a return value, + // Create a Command Context + var context = new CommandContext(client, message); + // Execute the command. (result does not indicate a return value, // rather an object stating if the command executed succesfully) - var result = await _commands.Execute(msg, argPos); + var result = await _commands.Execute(context, argPos); if (!result.IsSuccess) await msg.Channel.SendMessageAsync(result.ErrorReason); } diff --git a/docs/guides/samples/dependency_map_setup.cs b/docs/guides/samples/dependency_map_setup.cs index 04722d79e..af791990e 100644 --- a/docs/guides/samples/dependency_map_setup.cs +++ b/docs/guides/samples/dependency_map_setup.cs @@ -1,6 +1,7 @@ using Discord; using Discord.Commands; using Discord.WebSocket; +using foxboat.Services; public class Commands { @@ -8,10 +9,16 @@ public class Commands { var commands = new CommandService(); var map = new DependencyMap(); - map.Add(client); - var self = await client.GetCurrentUserAsync(); - map.Add(self); + map.Add(client); + map.Add(commands); await commands.LoadAssembly(Assembly.GetCurrentAssembly(), map); } + // In ConfigureServices, we will inject the Dependency Map with + // all of the services our client will use. + public Task ConfigureServices(IDependencyMap map) + { + map.Add(new NotificationService(map)); + map.Add(new DatabaseService(map)); + } // ... } \ No newline at end of file diff --git a/docs/guides/samples/faq/avatar.cs b/docs/guides/samples/faq/avatar.cs index 3e775c058..d3995cf0c 100644 --- a/docs/guides/samples/faq/avatar.cs +++ b/docs/guides/samples/faq/avatar.cs @@ -1,5 +1,5 @@ public async Task ChangeAvatar() { var fileStream = new FileStream("./newAvatar.png", FileMode.Open); - await (await _client.GetCurrentUserAsync()).ModifyAsync(x => x.Avatar = fileStream); + await _client.CurrentUser.ModifyAsync(x => x.Avatar = fileStream); } \ No newline at end of file diff --git a/docs/guides/samples/faq/guild_from_message.cs b/docs/guides/samples/faq/guild_from_message.cs deleted file mode 100644 index f224c95e3..000000000 --- a/docs/guides/samples/faq/guild_from_message.cs +++ /dev/null @@ -1,4 +0,0 @@ -public async Task MessageReceived(IMessage msg) -{ - var guild = (msg.Channel as IGuildChannel)?.Guild; -} \ No newline at end of file diff --git a/docs/guides/samples/faq/send_message.cs b/docs/guides/samples/faq/send_message.cs index d24c1cf6b..ed4ff9b8a 100644 --- a/docs/guides/samples/faq/send_message.cs +++ b/docs/guides/samples/faq/send_message.cs @@ -1,6 +1,6 @@ public async Task SendMessageToChannel(ulong ChannelId) { - var channel = await _client.GetChannelAsync(ChannelId) as IMessageChannel; + var channel = _client.GetChannel(ChannelId) as ISocketMessageChannel; await channel?.SendMessageAsync("aaaaaaaaahhh!!!") /* ^ This question mark is used to indicate that 'channel' may sometimes be null, and in cases that it is null, we will do nothing here. */ } \ No newline at end of file diff --git a/docs/guides/samples/groups.cs b/docs/guides/samples/groups.cs index 4967af608..b04148d26 100644 --- a/docs/guides/samples/groups.cs +++ b/docs/guides/samples/groups.cs @@ -1,15 +1,15 @@ -[Module("admin")] -public class AdminModule +[Group("admin")] +public class AdminModule : ModuleBase { [Group("mod")] - public class ModerationGroup + public class ModerationGroup : ModuleBase { // ~admin mod ban foxbot#0282 [Command("ban")] - public async Task Ban(IUserMessage msg, IGuildUser user) { } + public async Task Ban(IGuildUser user) { } } // ~admin clean 100 [Command("clean")] - public async Task Clean(IUserMessage msg, int count = 100) { } + public async Task Clean(int count = 100) { } } \ No newline at end of file diff --git a/docs/guides/samples/module.cs b/docs/guides/samples/module.cs index 282a322c9..66d2907df 100644 --- a/docs/guides/samples/module.cs +++ b/docs/guides/samples/module.cs @@ -1,29 +1,29 @@ +using Discord; using Discord.Commands; using Discord.WebSocket; // Create a module with no prefix -[Module] -public class Info +public class Info : ModuleBase { // ~say hello -> hello [Command("say"), Summary("Echos a message.")] - public async Task Say(IUserMessage msg, - [Unparsed, Summary("The text to echo")] string echo) + public async Task Say([Unparsed, Summary("The text to echo")] string echo) { - await msg.Channel.SendMessageAsync(echo); + // ReplyAsync is a method on ModuleBase + await ReplyAsync(echo); } } // Create a module with the 'sample' prefix -[Module("sample")] -public class Sample +[Group("sample")] +public class Sample : ModuleBase { - // ~sample square 20 -> + // ~sample square 20 -> 400 [Command("square"), Summary("Squares a number.")] - public async Task Square(IUserMessage msg, - [Summary("The number to square.")] int num) + public async Task Square([Summary("The number to square.")] int num) { - await msg.Channel.SendMessageAsync($"{num}^2 = {Math.Pow(num, 2)}"); + // We can also access the channel from the Command Context. + await Context.Channel.SendMessageAsync($"{num}^2 = {Math.Pow(num, 2)}"); } // ~sample userinfo --> foxbot#0282 @@ -34,10 +34,9 @@ public class Sample // ~sample whois 96642168176807936 --> Khionu#8708 [Command("userinfo"), Summary("Returns info about the current user, or the user parameter, if one passed.")] [Alias("user", "whois")] - public async Task UserInfo(IUserMessage msg, - [Summary("The (optional) user to get info for")] IUser user = null) + public async Task UserInfo([Summary("The (optional) user to get info for")] IUser user = null) { - var userInfo = user ?? await Program.Client.GetCurrentUserAsync(); - await msg.Channel.SendMessageAsync($"{userInfo.Username}#{userInfo.Discriminator}"); + var userInfo = user ?? Context.Client.CurrentUser; + await ReplyAsync($"{userInfo.Username}#{userInfo.Discriminator}"); } } \ No newline at end of file diff --git a/docs/guides/samples/require_context.cs b/docs/guides/samples/require_context.cs index ee02db8e8..0bc558e4a 100644 --- a/docs/guides/samples/require_context.cs +++ b/docs/guides/samples/require_context.cs @@ -1,11 +1,10 @@ -[Module] -public class InfoModule +public class InfoModule : ModuleBase { // Constrain this command to Guilds [RequireContext(ContextType.Guild)] - public async Task Whois(IUserMessage msg, IGuildUser user) { } + public async Task Whois(IGuildUser user) { } // Constrain this command to either Guilds or DMs [RequireContext(ContextType.Guild | ContextType.DM)] - public async Task Info(IUserMessage msg) { } + public async Task Info() { } } \ No newline at end of file diff --git a/docs/guides/samples/require_owner.cs b/docs/guides/samples/require_owner.cs index ede18d25f..670d92c19 100644 --- a/docs/guides/samples/require_owner.cs +++ b/docs/guides/samples/require_owner.cs @@ -1,16 +1,18 @@ // Defining the Precondition -// Specify that this precondition can target a Class (Module/Group) or Method (Command) -[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)] // Inherit from PreconditionAttribute public class RequireOwnerAttribute : PreconditionAttribute { - public readonly ulong OwnerId = 66078337084162048; - // Override the CheckPermissions method - public override Task CheckPermissions(IUserMessage context, Command executingCommand, object moduleInstance) + public override Task CheckPermissions(CommandContext context, CommandInfo command, IDependencyMap map) { - // If the author of the message is '66078337084162048', return success; otherwise fail. - return Task.FromResult(context.Author.Id == OwnerId ? PreconditionResult.FromSuccess() : PreconditionResult.FromError("You must be the owner of the bot.")); + // Get the ID of the bot's owner + var ownerId = (await map.Get().GetApplicationInfoAsync()).Owner.Id; + // If this command was executed by that user, return a success + if (context.User.Id == ownerId) + return PreconditionResult.FromSuccess(); + // Since it wasn't, fail + else + return PreconditionResult.FromError("You must be the owner of the bot to run this command."); } } \ No newline at end of file diff --git a/docs/guides/samples/require_permission.cs b/docs/guides/samples/require_permission.cs index 136b80088..56a1ff744 100644 --- a/docs/guides/samples/require_permission.cs +++ b/docs/guides/samples/require_permission.cs @@ -1,7 +1,6 @@ -[Module] -public class AdminModule +public class AdminModule : ModuleBase { [Command("ban")] [RequirePermission(GuildPermission.BanMembers)] - public async Task Ban(IUserMessage msg) { } + public async Task Ban(IGuildUser target) { } } \ No newline at end of file diff --git a/docs/guides/samples/typereader.cs b/docs/guides/samples/typereader.cs index c5b958283..69db3b991 100644 --- a/docs/guides/samples/typereader.cs +++ b/docs/guides/samples/typereader.cs @@ -3,7 +3,7 @@ using Discord.Commands; public class BooleanTypeReader : TypeReader { - public override Task Read(IUserMessage context, string input) + public override Task Read(CommandContext context, string input) { bool result; if (bool.TryParse(input, out result)) diff --git a/docs/guides/terminology.md b/docs/guides/terminology.md index 2633a56c6..a51003e34 100644 --- a/docs/guides/terminology.md +++ b/docs/guides/terminology.md @@ -9,17 +9,30 @@ title: Terminology Most terms for objects remain the same between 0.9 and 1.0. The major difference is that the ``Server`` is now called ``Guild``, to stay in line with Discord internally -## Introduction to Interfaces +## Implementation Specific Entities -Discord.Net 1.0 is built strictly around Interfaces. There are no methods that return a concrete object, only an interface. +Discord.Net 1.0 is split into a core library, and three different +implementations - Discord.Net.Core, Discord.Net.Rest, Discord.Net.Rpc, +and Discord.Net.WebSockets. -Many of the interfaces in Discord.Net are linked through inheritance. For example, @Discord.IChannel represents any channel in Discord. @Discord.IGuildChannel inherits from IChannel, and represents all channels belonging to a Guild. As a result, @Discord.IChannel can sometimes be cast to @Discord.IGuildChannel, and you may find yourself doing this frequently in order to properly utilize the library. +As a bot developer, you will only need to use Discord.Net.WebSockets, +but you should be aware of the differences between them. -### The Inheritance Tree +`Discord.Net.Core` provides a set of interfaces that model Discord's +API. These interfaces are consistent throughout all implementations of +Discord.Net, and if you are writing an implementation-agnostic library +or addon, you can rely on the core interfaces to ensure that your +addon will run on all platforms. -You may want to familiarize yourself with the inheritance in Discord.Net. An inheritance tree is provided below. +`Discord.Net.Rest` provides a set of concrete classes to be used +**strictly** with the REST portion of Discord's API. Entities in +this implementation are prefixed with `Rest`, e.g. `RestChannel`. -![](https://i.lithi.io/kpgd.png) -![](https://i.lithi.io/kNrr.png) -![](https://i.lithi.io/gs8d.png) -![](https://i.lithi.io/LAJr.png) \ No newline at end of file +`Discord.Net.Rpc` provides a set of concrete classes that are used with +Discord's RPC API. Entities in this implementation are prefixed with +`Rpc`, e.g. `RpcChannel`. + +`Discord.Net.WebSocket` provides a set of concrete classes that are used +primarily with Discord's WebSocket API, or entities that are kept in +cache. When developing bots, you will be using this implementation. All +entities are prefixed with `Socket`, e.g. `SocketChannel`. \ No newline at end of file diff --git a/docs/migrating.md b/docs/migrating.md index c69b8a59c..8f96dff98 100644 --- a/docs/migrating.md +++ b/docs/migrating.md @@ -5,11 +5,6 @@ changes in the design of the library.** >A medium to advanced understanding is recommended when working with this library. -One of the biggest major changes from `0.9.x` is the exclusive use of interfaces. -For the most part, your usability will be very similar to the 0.9 approach of concrete -classes. You **will** be required to cast some entities; this is outlined in a later -section. - It is recommended to familiarize yourself with the entities in 1.0 before continuing. Feel free to look through the library's source directly, look through IntelliSense, or look through our hosted [API Documentation](xref:Discord). @@ -19,8 +14,7 @@ look through our hosted [API Documentation](xref:Discord). Most API models function _similarly_ to 0.9, however their names have been changed. You should also keep in mind that we now separate different types of Channels and Users. -Take a look at inheritance section of @Terminology for an example of how inheritance and interfaces -work in 1.0 +Before proceeding, please read over @Terminology to understand the naming behind some objects. Below is a table that compares most common 0.9 entities to their 1.0 counterparts. @@ -29,18 +23,16 @@ Below is a table that compares most common 0.9 entities to their 1.0 counterpart | 0.9 | 1.0 | Notice | | --- | --- | ------ | -| Server | @Discord.IGuild | -| Channel | @Discord.IGuildChannel | Applies only to channels that are members of a Guild | -| Channel.IsPrivate | @Discord.IDMChannel -| ChannelType.Text | @Discord.ITextChannel | This applies only to Text Channels in Guilds -| ChannelType.Voice | @Discord.IVoiceChannel | This applies only to Voice Channels in Guilds -| User | @Discord.IGuildUser | This applies only to users belonging to a Guild* -| Profile | @Discord.ISelfUser -| Message | @Discord.IUserMessage - -\* To retrieve an @Discord.IGuildUser, you must retrieve the user from an @Discord.IGuild. -[IDiscordClient.GetUserAsync](xref:Discord.IDiscordClient#Discord_IDiscordClient_GetUserAsync_System_UInt64_) -returns a @Discord.IUser, which only contains the information that Discord exposes for public users. +| Server | @Discord.WebSocket.SocketGuild | +| Channel | @Discord.WebSocket.SocketGuildChannel | Applies only to channels that are members of a Guild | +| Channel.IsPrivate | @Discord.WebSocket.SocketDMChannel +| ChannelType.Text | @Discord.WebSocket.SocketTextChannel | This applies only to Text Channels in Guilds +| ChannelType.Voice | @Discord.WebSocket.SocketVoiceChannel | This applies only to Voice Channels in Guilds +| User | @Discord.WebSocket.SocketGuildUser | This applies only to users belonging to a Guild* +| Profile | @Discord.WebSocket.SocketGuildUser +| Message | @Discord.WebSocket.SocketUserMessage + +\* To retrieve an @Discord.WebSocket.SocketGuildUser, you must retrieve the user from an @Discord.WebSocket.SocketGuild. ## Event Registration @@ -67,15 +59,3 @@ API docs before implementing it. ## Async Nearly everything in 1.0 is an async Task. You should always await any tasks you invoke. - -However, when using WebSockets, you may find this both inconvienent, and unnecessary, as many of the -WebSocket implementations of the interfaces keep their own local cache of objects, rendering the use -of async redundant. - -**As of right now,** there are extension methods you can use, located in `Discord.WebSocket` that will -provide java-esque, synchronus `GetXXX` methods to replace the asynchronus methods on WebSocket entities. - -This functionality may be changed at a later date, we are currently reviewing this implementation and -alternative methods. - -For your reference, you may want to look through the extension classes located in @Discord.WebSocket