From 289dbff4e3269368dc33de39927a180be92b67dd Mon Sep 17 00:00:00 2001 From: jacob Date: Fri, 15 Mar 2024 13:26:47 -0500 Subject: [PATCH] scrap ttt --- docs/tutorial/en/05-tictactoe/command.md | 43 -------- docs/tutorial/en/05-tictactoe/logic.md | 106 ------------------ docs/tutorial/en/05-tictactoe/plugins.md | 54 --------- docs/tutorial/en/05-tictactoe/tictactoe.md | 24 ---- docs/tutorial/en/05-tictactoe/ui.md | 122 --------------------- 5 files changed, 349 deletions(-) delete mode 100644 docs/tutorial/en/05-tictactoe/command.md delete mode 100644 docs/tutorial/en/05-tictactoe/logic.md delete mode 100644 docs/tutorial/en/05-tictactoe/plugins.md delete mode 100644 docs/tutorial/en/05-tictactoe/tictactoe.md delete mode 100644 docs/tutorial/en/05-tictactoe/ui.md diff --git a/docs/tutorial/en/05-tictactoe/command.md b/docs/tutorial/en/05-tictactoe/command.md deleted file mode 100644 index e28cf2522..000000000 --- a/docs/tutorial/en/05-tictactoe/command.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -title: command -sidebar_position: 2 ---- - -import GuideFeedback from "../../../../src/components/GuideFeedback"; - -# Commands - -## Example command -- View the command **ping.js** in `src/commands`. -- Make a new file next to **ping.js** called **tictactoe.js** -- Copy **ping.js** contents into **tictactoe.js**. -We base **tictactoe.js** from **ping.js** - -:::tip -The name of your command will be the name of your file. -::: - -Each slash command will follow this similar structure. -In this tutorial, maybe you were smart enough to guess, but we'll be making tictactoe! - -## New command, tic-tac-toe -- Instead of **CommandType.Both**, `type` property should be **CommandType.Slash** - - This is to keep it simple. You'll see later, but slash commands work well with message components. -- Give it a description. -- run `npm run commands:publish` -- Your command should be usable on discord now! - -### Result -Your command should now look something along the lines of this: -```js title=./commands/tictactoe.js -export default commandModule({ - type: CommandType.Slash, - description: "I do tictactoe.", - execute: async (ctx) => { - await ctx.reply("Pwease wait. dis command in pwogwess"); // 👻 - } -}) -``` - ---- - \ No newline at end of file diff --git a/docs/tutorial/en/05-tictactoe/logic.md b/docs/tutorial/en/05-tictactoe/logic.md deleted file mode 100644 index a30c3c047..000000000 --- a/docs/tutorial/en/05-tictactoe/logic.md +++ /dev/null @@ -1,106 +0,0 @@ ---- -title: Logic -sidebar_position: 5 ---- - -import GuideFeedback from "../../../../src/components/GuideFeedback"; - -## Game rules -- Two players max. -- Each player is assigned **X** or **O** -- The first person to get 3 in a row of their letter wins. - -Get the option selected, adding this to the top of your **execute** function: -```js -const opponent = ctx.options.getUser("opponent"); -``` -:::warning -Since we are in a Slash command, the above is valid. If we were to interoperate between Text Commands and Slash Commands, -we'd have to check if the current [Context](https://sern.dev/docs/api/classes/Context) is the correct type. In our current setup, -this won't happen since we did not set our command type to **Both**. -::: - -We need to ensure we're not playing against **an invalid user**. Invalid users are those that -- are bots **or** -- ourselves. - -Create helper function **isInvalidUser** which returns a boolean satisfying the conditions above. - -```js -const isInvalidUser = (user) => { - return user.id === "182326315813306368" || user.bot; -} -``` -:::tip -You can easily access anyone's user id by [enabling dev mode](https://beebom.com/how-enable-disable-developer-mode-discord). -::: - -Cool, now let's call it, preventing invalid users from being opponents. Put the code snippet before any of the UI logic: -```js title="tictactoe, execute function" -if(isInvalidUser(opponent)) { - return; -} -``` -We **return**, or **stop** execution of the function if the condition `isInvalidUser` is true. -:::info -A step further would be extracting `isInvalidUser` into a separate plugin, if multiple commands share this same logic. -::: -Before we go any further, let's test. Start up the bot again. -- Try running `/tictactoe` with a bot. - - What happens? - - It may be beneficial to give the user some feedback instead of a **return**. -- Try running `/tictactoe` with yourself - - What happens? - - It may be beneficial to give the user some feedback instead of a **return**. -- Try running `/tictactoe` in a DM channel with the bot itself. - - What happens? - -Great! notice how in a DM channel, the command is entirely **useless**. -Let's use our **channelType** plugin to ensure this doesn't happen. -- Add the **plugins** field to your commandModule, adding the channelType plugin. -```js -plugins: [channelType( )] -``` -- Call it with the right parameters. - - All plugins come with documentation in the same file - - In our case, we need to supply an array of ChannelTypes, and an optional message. -```js -plugins: [channelType([ChannelType.GuildText], "You cannot execute this command here.")] -``` -:::info -You can publish commands to specific guilds using special configuration. -For more information, view the docs [here](https://sern.dev/docs/cli/publish). -For educational and simplicity purposes, I'm using a plugin here. -::: - -Great! When we rerunning these test conditions, it should catch and respond to these conditions. - - -## Collectors -We know how to display components, but what about responding to them? -Discord.js gives us the Collector API, which at its core, listens to incoming interactions from discord.js. It essentially comes in two flavors. -- **await** -- **callback based** - -**Await** is [easy](https://www.infoq.com/presentations/Simple-Made-Easy/), but it comes at the cost of only collecting `one` at a time. Also, -it is blocking on other commands attempting to be run; When we await a component, -All other commands will be waiting as well. So, we'll be using callback based, lazily waiting. Let's create a collector to the message sent by the bot. How do we get that message? -Luckily `ctx.reply` returns the [Message](https://discord.js.org/#/docs/discord.js/main/class/Message) sent. Let's capture that in a variable. - -- Capture the result of ctx.reply in a variable called **resultMessage**. -```js -const resultMessage = await ctx.reply({ message, components: grid }); -``` -- Create a collector from the message's property `.createMessageComponentCollector()` - - Accept only interactions of type **Button** (we are making a tictactoe game of solely buttons), - - Make sure to import **ComponentType** from discord.js - - Give it a time limit of 60_000 milliseconds aka 1 minute. -```js -// verbosity!! //ignore this -const collector = responseMessage.createMessageComponentCollector({ - componentType: ComponentType.Button, - time: 60_000 -}); -``` ---- - \ No newline at end of file diff --git a/docs/tutorial/en/05-tictactoe/plugins.md b/docs/tutorial/en/05-tictactoe/plugins.md deleted file mode 100644 index 3e8984303..000000000 --- a/docs/tutorial/en/05-tictactoe/plugins.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -title: plugins -sidebar_position: 3 ---- - -import GuideFeedback from "../../../../src/components/GuideFeedback"; - -# What are plugins? - -## Code ran before a command to modify output. - - -sern has a bunch of premade plugins thanks to our awesome community, which you can install via the cli! - -## Forward: - -- Run: `sern plugins`, selecting the **channelType** plugin -- Thank the creator(s) of the plugin. (Thank you) -- Import your plugin at the top of the file like this -```js -import { channelType } from '../plugins/channelType.js' -``` - -Once you download the `channelType` plugin, You may continue. - -## Aside: - -### How to use plugins? -Lets take an aside to show how to install plugins. -- Run: `sern plugins`, selecting plugins -- Thank the creator(s) of the plugin. (Thank you) - -```js -import { commandModule, CommandType } from '@sern/handler' -import { channelType } from '../plugins/channelType.js' - -export default commandModule({ - type: CommandType.Slash, - description: "haliburt", - // here: - plugins: [channelType([ChannelType.GuildText], 'This cannot be used here')] -}) - -``` -Keep in mind some plugins cannot run for every type of interaction sern handles. -For example, the **channelType** plugin will probably not work in a modal, and if you are using typescript, -the type checker won't allow it. However, there are some more generic plugins, one being **fromCallback**, which can -run in any command / component. - -### How to contribute plugins?: -- view [here](../../../guide/walkthrough/plugins). - ---- - \ No newline at end of file diff --git a/docs/tutorial/en/05-tictactoe/tictactoe.md b/docs/tutorial/en/05-tictactoe/tictactoe.md deleted file mode 100644 index 35b689932..000000000 --- a/docs/tutorial/en/05-tictactoe/tictactoe.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -title: intro -sidebar_position: 1 ---- - -import GuideFeedback from "../../../../src/components/GuideFeedback"; - -> How hard can this be? - -This will probably be the longest chapter in the guide. Don't worry though, once we're done, making commands is [**fodder**](https://www.merriam-webster.com/dictionary/fodder). - -Here are some inspirational quotes to make you get motivated. -> "If you don't make mistakes, you're not working on hard enough problems." ― Frank Wilczek - -> "Dwell on the beauty of life. Watch the stars, and see yourself running with them." ― Marcus Aurelius, Meditations - -> "Never let the future disturb you. You will meet it, if you have to, with the same weapons of reason which today arm you against the present." ― Marcus Aurelius, Meditations - -If you want to add more, feel free to pull request this, but not too many please! - -TODO!!! - ADD TIC TAC TOE GIF HERE - ---- - \ No newline at end of file diff --git a/docs/tutorial/en/05-tictactoe/ui.md b/docs/tutorial/en/05-tictactoe/ui.md deleted file mode 100644 index b1369d1fc..000000000 --- a/docs/tutorial/en/05-tictactoe/ui.md +++ /dev/null @@ -1,122 +0,0 @@ ---- -title: UI -sidebar_position: 4 ---- - -import GuideFeedback from "../../../../src/components/GuideFeedback"; - -## Message Components - -Discord has a rich api for developers, and they allow bots to use and interact with certain UI components. -Some of these include - -- Buttons -- Modals (technically not a component) -- Select Menu -- Action Rows - -Let's use the mush we call [**brain**](https://www.ninds.nih.gov/health-information/public-education/brain-basics/brain-basics-know-your-brain). - -> **Question**: What components do we need to create a tic tac toe game? - -> **Answer**: Buttons!!!! - - -### Rules -Obviously we can't spam the user interface with lots of components; Discord knows this as well. - -Per the [**discord api documentation**](https://discord.com/developers/docs/interactions/message-components#action-rows): -- You can have up to 5 Action Rows per message -- Maximum of **5** components in an Action Row -- An Action Row cannot contain another Action Row -- Select Menus take up an entire Action Row, and cannot have buttons - - -Do the math, and we can have up to 5 (action rows) times 5 (per row), 25 buttons in one message - -### Custom Ids -We also need some way to distinguish buttons between other buttons. Whenever a user clicks a button, we are notified that **some** interaction has happened, but from **where?** Custom ids to the rescue. Think of these like 'classes' or 'ids' on html tags. **Each component that we need to handle -will have to be retrieved by their custom id in order to properly handle it** - - -We'll get more into this in the next chapter. - - -### Design -Our UI will contain a message, and a total of 9 buttons, laid out in a 3x3 grid. - -TODO!!! PICTURE HERE - - -### Implementation - -How do we represent this in code? In discord.js, the library we're using, we can represent this via their builder api. Let's create some utility functions before diving straight in. - -```js title="tictactoe.js" -const EMPTY = "\0"; // A little trick to show buttons with no 'label' -const button = (custom_id, label=EMPTY) => { - return new ButtonBuilder({ - custom_id, - label, - style: ButtonStyle.Secondary - }); -} - -const row = (...elements) => { - return new ActionRowBuilder().addComponents(elements); -} -``` -The names for these are pretty self explanatory. **EMPTY** is a placeholder for labels in a button. - -In our **execute** function, let's build the Action Rows. -```js title="tictactoe.js, in the execute body" -const message = "Tic Tac Toe"; - -//Our TicTacToe grid. consists of 3 rows, and in each row, 3 buttons. -//Each button has a unique 'customId' of a number. -const grid = [row(button('0'), button('1'), button('2')), - row(button('3'), button('4'), button('5')), - row(button('6'), button('7'), button('8'))]; - - -await ctx.reply("Pwease wait. dis command in pwogwess"); // 👻 -``` -> Question: Does this grid satisfy the rules stated above? - -> Answer: Yes! We have 3 Action Rows in total, with 3 Buttons in each. Less than 25 Components! - -Let's try displaying this to Discord. We're not just displaying plain text anymore, we need to change ctx.reply. - -- Change how we call `ctx.reply`. Give it an object instead: -```js -// await ctx.reply("Pwease wait. dis command in pwogwess"); // 👻 - -await ctx.reply({ content: message, components: grid }); -``` -One more thing, we need to play against someone, so we'll need to update our commandModule. -- Add the import **ApplicationCommandOptionType** from discord.js -- Add a new **option** of type **User** to the **options** field of your commandModule. -This will display on the user's end as an option to choose from. -```js -options: [ - { - name: "opponent", - description: "Opponent you would like to play with", - type: ApplicationCommandOptionType.User, - required: true, - }, -], -``` -- Run `npm run commands:publish` once more to update it. - -:::tip -Anytime we add a new slash command or its options, its a good idea to run `npm run commands:publish` -::: - -Run your bot. -- Congrats! You got something to display. -Notice how when you try to click, it will say something like `interaction failed to respond`. -**Next chapter**, let's wire everything up. - ---- - \ No newline at end of file