Discord.js - Get Message from Interaction - javascript

client.ws.on('INTERACTION_CREATE', async (interaction) => {}
The interaction class has lots of properties like channel, member and id but it doesn't have a message property.
Is there a way to get the message from an interaction or will I have to use a event listener on message? And if so, how would I use this with slash commands?

You can get the user input by just using the base class interaction. However, the content is not visible, but you can view it by passing it through an api endpoint or something similar, its kind of weird for me but i'm sure there is an explanation for that.
The best way is to use interaction.options, so you'll need to add at least one option in your application command.
For example
// /test as your Application command
client.on('interactionCreate', async interaction => {
if (interaction.commandName === 'test') {
const message = interaction.options.data
console.log(message)
})
}

Slash commands have their own type of message. I don’t believe they have an id, delete button, edit button or lots of things most messages do. This means you will not be able to get the "message" from a slash command. From buttons however, they do emit INTERACTION_CREATE but has a little more info. I don’t remember for sure, but I think you can use something like interaction.components. I am not completely sure, but if you want, click a button and log the interaction into your console to see the unique button info like this
client.ws.on('INTERACTION_CREATE', async (interaction) => {
{
console.log(interaction) //will be long!
//…
})

Related

Discord.js Bot can't handle multiple buttons in the same channel (Version 13)

Is there a way to have a command with buttons be used by two people at the same time in the same channel?
I made an adventure system which is going well so far, but I found out that only one person can use it in a channel. If another person uses it in the same channel, the "DiscordAPIError: Unknown Interaction" error comes as soon as a button is used. I tried adding the message author's id to the custom ID of the buttons, but it still doesn't work for some reason and I am utterly confused.
From what I understand, I think it's unrelated to there being multiple button instances, but I can't think of any other reason. Here is the filter:
const filter = async (interaction) => {
if (interaction.user.id === message.author.id) return true;
await interaction.deferReply()
await interaction.editReply({ content: `**${interaction.user.username}**, You can't use this button!`, ephemeral: true})
return false
}
And the button click detector goes something like this:
GameCollect.on('collect', async ButtonInteraction => {
ButtonInteraction.deferUpdate()
// My code
})
I have tried:
Removing ButtonInteraction.deferUpdate() from all my click collectors.
Making the custom ids for the buttons have the message author's id at the end and making my code compatible with that change.
Smashing my head on my keyboard from confusion. Didn't work either... (satire)
If it's necessary, I can copy my code into a repl so that you can identify the problem easier, but I don't think the other portions would have any effect on this. I think it's just a piece of code/slight adjustment that I have to add for it to work with two people in the same channel.
EDIT: Alright, here is a source bin so that you can identify the problem better. Check the comments on the recent answer for some clarifications on my testing too. I will keep you updated if I find a solution.
DISCLAIMER: I still haven't found a way to make this work in over a month, and I am essentially just giving up on buttons. Thank you to everyone who helped though.
Try it:
Remove await interaction.deferReply() from filter
Create dynamic customIds like Math.random()
EDIT:
description: i had the same issue recently on my own bot, The problem is that when 2 messages that the have collectors(basically they're waiting for a interaction), if you call await interaction.deferReply() soon, it wil get messy, So here's the solution
First of all lets go for the filter function for checking the interaction, We need 2 things:
Checking the button id with the incoming interaction button id
Checking the user to be the real one
After all of these
delete deferReply from the filter func, Because when you didn't check the interactions, calling deferReply, will call both of messages or all of the messages that are waiting for interaction
add the deferReply to the function that is after filter
And don't remember to use random ids for components(Buttons, select menus and ...)
Instead of creating a collector on the text channel, you should create the collector on the actual message
const GameCollect = message.channel.createMessageComponentCollector({ filter, time: 60000 * 15 })
To
const GameCollect = <Message>.createMessageComponentCollector({ filter, time: 60000 * 15 })

Discord.js : Move message to bottom of Text-Channel

I want to move a specific message (identified by an ID) to the bottom of the text-channel it is in. As if it was newly posted. (This will be triggered by command)
Pinning is not a solution, because that does not pin the message to the bottom of the chat as one might think. It just adds it to a list of pinned messages, only visible by clicking the pin icon, which pretty much noone does unless they're told to.
Reposting the message isn't a solution, because it has a lot of User-Reactions under it, which should remain. I have not yet found a way to transfer all reactions from one message to another, and, looking at the Discord.js Documentation, I don't think it is possible. You can't even fake-react as a user, let alone add multiple reactions at once.
Howevery simply moving a message to the bottom of the text-channel might be possible, although i cannot find a method for it either. But maybe I've just overlooked something.
Is it possible, and if yes, how?
Seeing what you need the only possible solution is the one I propose below, since discord does not allow you to do what you want to do literally.
Something like this but answered by the bot:
Using discord-reply: https://www.npmjs.com/package/discord-reply
const discord = require('discord.js');
require('discord-reply'); //⚠️ IMPORTANT: put this before your discord.Client()
const client = new discord.Client();
client.on('ready', () => {
console.log(client.user.tag)
});
client.on('message', async message => {
if (message.content.startsWith('!reply')) {
message.lineReply('Hey'); //Line (Inline) Reply with mention
message.lineReplyNoMention(`My name is ${client.user.username}`); //Line (Inline) Reply without mention
}
});
client.login('TOKEN');
On command handler
/**
* No need to define it
* */
module.exports = {
name: 'reply',
category: 'Test',
run: (client, message, args) => {
message.lineReply('This is reply with #mention');
}
}
Credits: discord.js | Reply to Message (Actual Reply with Reply Decoration

Discord.js - Secretly getting user input

I am making a 2-player rock-paper-scissors game using Discord.js.
Sadly the Discord API is really slow and afaik doesn't provide any type of middleware. When someone chooses their shape, the other person sees the reaction (or chat message) for quite a while until the bot deletes it, therefore ruining the whole game.
The only way of secretly getting an input I could think of, was sending the user a message in private chat, to which he can react. But having to switch from the server to private chat and then back to the server just makes the game unplayable in my opinion. It's just too much work for the user, compared to simply clicking a reaction.
Another option would be sending a message in the chat, which only a specific user can see. It could say something like "1 = Scissors, 2 = Rock, 3 = Paper". (The mapping would be randomized for each player). The user then picks the corresponding reaction from the options 1, 2 and 3.
But it seems, Discord does not allow to send a message in chat, which only a specific user can see. Or is there a way?
And is there any way of secetly getting user-input without the user having to switch chats?
Does the API maybe provide any kind of middle-ware for messages or reactions which I have overlooked?
Discord does not allow to send a message in chat, which only a specific user can see. Or is there a way?
No, there isn't. Discord API doesn't allow you to specify users that can see a specific guild message.
And is there any way of secetly getting user-input without the user having to switch chats?
There definitely is!
You could use a fairly new feature, buttons. Below is an example code, you can use to base your game on. Things left to implement are:
Gamestate, e.g. who is on turn, who has how much points, etc.
Update gamestates (identify gamestate by id?) in the interactionCreate event's callback.
Showing the gamestate to the players, e.g. updating the original message.
Don't allow players to modify the gamestate of other playing pairs.
Let the user specify an opponent in !createGame command.
The actual game logic (determining who won, who gets a point, etc.)
That is all I can think of for now. Take those more of a suggestions than requirements. There is no boundary to ones creativity.
// ... Some object to store the gamestates in? ...
client.on("messageCreate", async (message) => {
// Don't reply to bots
if (message.author.bot) return;
// Basic command handler, just for showcasing the buttons
if (message.content.startsWith("!createGame")) {
// ... Probably some argument handling for the opponent (e.g. a mention) ...
// Create an action row component with buttons attached to it
const actionRow = new Discord.MessageActionRow()
.addComponents(
[["Rock", "🗿"], ["Paper", "🧻"], ["Scissors", "✂️"]].map((buttonProperties) => {
return new Discord.MessageButton()
.setStyle("PRIMARY")
.setLabel(buttonProperties[0])
.setEmoji(buttonProperties[1])
.setCustomId(`rpsgame_${buttonProperties[0].toLowerCase()}`);
})
);
// Send the game message/playground
message.channel.send({
content: "Rock, Paper and Scissors: The game!",
components: [actionRow]
});
}
});
To handle the button clicks, we use the interactionCreate event.
client.on("interactionCreate", (interaction) => {
// If the interaction is a button
if (interaction.isButton()) {
// If the button belongs to our game
if (interaction.customId.startsWith("rpsgame")) {
// Log what the user has selected to console, as a test
console.log(`A user '${interaction.member.user.tag}' selected ${interaction.component.emoji.name}.`);
// Don't forget to reply to an interaction,
// otherwise an error will be shown on discord.
interaction.update("Update GameState...");
}
}
});
No one will see what the other users have selected, unless you want them to.
Using discord.js ^13.0.1. If you are on v12, there is a nice package called discord-buttons.

How do I create a discord.js command in index.js [The bot's startup file] that deletes the message when a message that contains "hi" was sent

I've tried to create a command where the bot waits for a message that was sent until a message contained "thebotdeletesthismessage", the bot doesn't seem to do anything, the language I've used is node.js.
The bot doesn't really responds neither delete the message, I've tried to change the code a little bit, Still nothing, I need to know what I've done wrong here.
If you didn't understand something, Please let me know in the comments, And please don't close this topic, I really need help.
bot.on('message', message => {
if (message.content.starts("thebotdeletesthismessage")) {
message.delete
message.channel.send('No, dont send that.');
}
});
Change message.delete to message.delete().
First, there is no .starts() method, you probably want to use .startsWith(). Also, message.delete is not a property but a method, so you'll need to use parentheses after that.
The following code will delete every message that starts with "thebotdeletesthismessage" and sends a message instead:
bot.on('message', (message) => {
if (message.content.startsWith('thebotdeletesthismessage')) {
message.delete();
message.channel.send("No, don't send that.");
}
});

Permissions in Discord.js API?

I'm coding a Discord bot with discord.js/node (I'm fairly new).
I tried to setup a permissions system where you would need a specific role to make an if statement return true and allow the user to use a command or something else. I tried (this is just part of it):
if(message.author.roles.includes('role_id') {
COMMANDS
}
But it just gives me errors in the console (obviously)
If any of you know how to properly set a permissions system up in a efficient way, that would be appreciated!
To achieve this using an if conditional: if(message.member.roles.has([role_id]))
where [role_id] is a string (otherwise it will always return false)
There is an hasRole method on users: http://discordjs.readthedocs.io/en/8.2.0/docs_user.html
hasRole(role)
Shortcut of client.memberHasRole(member, role)
See client.memberHasRole
Which link to this: http://discordjs.readthedocs.io/en/8.2.0/docs_client.html#memberhasrole-member-role
memberHasRole(member, role)
Returns if a user has a role
Did you try doing something like this?
if (!message.member.roles.some(r=>["role_name"].includes(r.name)) )
return;
This will prevent all users from using that specific command unless they have the specified role.

Categories

Resources