Skip to content

Commit

Permalink
🎉 [1.5.0] - Slash commands
Browse files Browse the repository at this point in the history
- Working slash commands (https://support.discord.com/hc/en-us/articles/1500000368501-Slash-Commands-FAQ)
- Created folder /slashes with all 5 working slash commands
- Edited command handler to visual match with event handler
- Edited bot invite link to have permission for creating new slash commands
- Installed discord-api-types
- Installed @discordjs/builders and /rest
- Added interactionCreate event to listen for slash commands
- Not important bug fixes
- Updated readme.MD file with new "What can this bot do?" title
- Sorted to-do list and added marking points
  • Loading branch information
PetyXbronCZ committed Jan 28, 2022
1 parent f1bf87d commit c4501d8
Show file tree
Hide file tree
Showing 14 changed files with 573 additions and 51 deletions.
76 changes: 52 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,38 +1,66 @@
## [DOCUMENTATION HERE](https://petyxbron.gitbook.io/minecraft-bot/installation)
## [DOCUMENTATION HERE 🔗](https://petyxbron.gitbook.io/minecraft-bot/installation)

# Discord minecraft server bot
### Get info about your minecraft server with this discord bot!
# Custom Discord Minecraft bot
### *Get info about your minecraft server with this discord bot!*

This code could not be created without **Minecraft server util package**
This code uses **Minecraft server util package** for getting status of Minecraft servers
* minecraft-server-util package
* [Github Repository](https://github.com/PassTheMayo/minecraft-server-util)
* [npmjs package](https://www.npmjs.com/package/minecraft-server-util)
* [Author Github Profile](https://github.com/PassTheMayo)

## WHAT CAN THIS BOT DO?

- **Fully customizable [config](config.js)**
- Working **commands** with **custom prefix** + their **[slash commands]((https://support.discord.com/hc/en-us/articles/1500000368501-Slash-Commands-FAQ))**
- `ip` command for getting IP address of server
- `list` command for getting actual list of online players now
- `status` command for getting simple and clear overview of server
- `version` command for getting Minecraft version of server
- `vote` command for getting vote link for voting for server on Minecraft server list
- **Auto updating bot's status** with online and max players (setup in config with variables)

![Auto updating bot status](https://i.imgur.com/xNDVb2D.png)
![Bot status config variables](https://i.imgur.com/7TXaWTC.png)
- More Discord bot activites: `playing`, `listening`, `watching` and `competing`
- **Poll/Voting channel** with reactions

![Voting channel](https://4254518267-files.gitbook.io/~/files/v0/b/gitbook-28427.appspot.com/o/assets%2F-MbqA4Jea2-IO37rpuOb%2F-MejM8GdpoTFx3MovYuy%2F-MejY9Dg6WsJ5LJ7qIVO%2Fvoting-channel.gif?alt=media&token=2a1d71d6-7544-4ba4-a6ff-f468872121c6)
- Custom responses for each command, editable in [config file](config.js)
- **Auto updating status message** with player list

![Auto status messsage](https://i.imgur.com/L6gFK4Q.png)
- **Random** RGB **color of command embeds** (each message another)

![Random embed color](https://i.imgur.com/pA7h5rC.png)
- **Clear colorful console** logging

![minecraft-bot console](https://i.imgur.com/N17AfDn.png)

## HOW TO USE & INSTALL

### Go to our [documentation](https://petyxbron.gitbook.io/minecraft-bot/installation/install) and see.
[![Run on Repl.it](https://repl.it/badge/github/MrMazzone/dotreplit-example)](https://repl.it/github/PetyXbron/minecraft-bot)
*Repl will not be updated for node v16.*
*Repl will not be updated for node v16. (not needed with version [1.1.5](https://github.com/PetyXbron/minecraft-bot/commit/a14fe3024b561a2b5516fb2390431f6650afe8b9))*

## TO DO

* <s>Auto changing status message</s>
* <s>Status command</s>
* <s>IP address command</s>
* <s>Minecraft version command</s>
* <s>Player list command</s>
* <s>Vote link command</s>
* Poll/Voting command
* <s>Poll/Voting channel with reactions</s>
* AdminTeam applications
* Slash commands
* Send custom embed message command
* Send custom message/announcement command
* <s>Custom reply for ip, test and version command</s>
* <s>Installation with repl.it</s>
* Better test command variables (more process info - like uptime)
* <s>More text languages (or custom)</s>
* Create threads from every message in voting channel
* <s>Bot status (activity) for players online number</s>
* <s>Get invite link on bot start (available option in config)</s>
- [x] <s>Auto changing status message</s>
- [x] <s>Status command</s>
- [x] <s>IP address command</s>
- [x] <s>Minecraft version command</s>
- [x] <s>Player list command</s>
- [x] <s>Vote link command</s>
- [x] <s>Poll/Voting channel with reactions</s>
- [x] <s>Slash commands</s>
- [x] <s>Custom reply for ip, test and version command</s>
- [x] <s>Installation with repl.it</s>
- [x] <s>More text languages (or custom)</s>
- [x] <s>Bot status (activity) for players online number</s>
- [x] <s>Get invite link on bot start (available option in config)</s>
- [ ] Poll/Voting command
- [ ] AdminTeam applications
- [ ] Send custom embed message command
- [ ] Send custom message/announcement command
- [ ] Better test command variables (more process info - like uptime)
- [ ] Create threads from every message in voting channel
1 change: 0 additions & 1 deletion commands/status.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ const { commands } = require("../config");
const util = require('minecraft-server-util');
const Discord = require('discord.js');
const c = require('chalk');
const { Console } = require("console");

module.exports.config = {
name: "status", //Name of command - RENAME THE FILE TOO!!!
Expand Down
5 changes: 2 additions & 3 deletions commands/version.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
const { commands } = require("../config");
const Discord = require('discord.js');
const db = require('quick.db')
const util = require('minecraft-server-util')
const warn = require('chalk').keyword('yellow').bold
const util = require('minecraft-server-util');
const warn = require('chalk').keyword('yellow').bold;

module.exports.config = {
name: "version", //Name of command - RENAME THE FILE TOO!!!
Expand Down
1 change: 0 additions & 1 deletion commands/vote.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
const { commands } = require("../config");
const Discord = require('discord.js');
const { Server } = require("http");

module.exports.config = {
name: "vote", //Name of command - RENAME THE FILE TOO!!!
Expand Down
4 changes: 2 additions & 2 deletions config.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ module.exports = {
statusCH: false, //Enable auto-changing status message
votingCH: false //Enable voting channel
},

//Period of auto changing status if you are using {onlinePlayers} or {maxPlayers} in bot's status
autoStatus: {
time: '10min'
},

//Voting channel - https://docs.petyxbron.cz/config/config-info#voting-ch
votingCH: {
time: '30s', //Time for how long the cancel reaction should be deleted.
Expand Down
6 changes: 6 additions & 0 deletions events/interactionCreate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = async (bot, interaction) => {
if (!interaction.isCommand()) return;

const command = bot.slashes.get(interaction.commandName);
if(command) command.run(bot,interaction);
}
2 changes: 1 addition & 1 deletion events/ready.js
Original file line number Diff line number Diff line change
Expand Up @@ -298,5 +298,5 @@ module.exports = async (bot) => {
}

console.log("✅ " + gr(bot.user.username) + " is now working with prefix " + gr(bot.prefix))
if(settings.inviteLink) console.log("️ " + " Invite " + chalk.blue.bold(bot.user.username) + " on " + chalk.blue.bold(`https://discord.com/oauth2/authorize?client_id=${bot.user.id}&scope=bot&permissions=11328`))
if(settings.inviteLink) console.log("️ " + " Invite " + chalk.blue.bold(bot.user.username) + " with " + chalk.blue.bold(`https://discord.com/oauth2/authorize?client_id=${bot.user.id}&scope=bot&permissions=11328&scope=applications.commands%20bot`))
}
54 changes: 36 additions & 18 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ const Discord = require('discord.js'),
fs = require('fs'),
c = require('chalk'),
ms = require('ms'),
{ REST } = require('@discordjs/rest'),
{ Routes } = require('discord-api-types/v9'),
Intents = Discord.Intents

//Discord client - I like "bot" more, then "client"
Expand All @@ -19,6 +21,7 @@ let info = config.statusCH

bot.commands = new Discord.Collection();
bot.aliases = new Discord.Collection();
bot.slashes = new Discord.Collection();
bot.token = config.bot.token;
bot.prefix = config.bot.prefix;
bot.status = config.bot.status;
Expand Down Expand Up @@ -171,30 +174,45 @@ bot.info = info
bot.text = config.messages

//Event handler
const eventsFolder = fs.readdirSync('./events'); //Finds files in event folder
const eventsFolder = fs.readdirSync('./events').filter(file => file.endsWith('.js'));
for (const file of eventsFolder) {
const eventFile = require(`./events/${file}`); //The file
const eventFile = require(`./events/${file}`);
const event = file.split(".")[0]
bot.on(event, eventFile.bind(null, bot)); //Runs the file
bot.on(event, eventFile.bind(null, bot));
};

//Command handler
fs.readdir("./commands/", (err, files) => {
if(err) console.log(err);
let jsfile = files.filter(f => f.split(".").pop() === "js");
jsfile.forEach((f, i) => {
let pull = require(`./commands/${f}`);
if(pull.config.enable) {
if(!pull.config.name) {
if(warns) console.log(warn(`Missing command name of file '${f}'!`) + '\nCommand disabled.')
} else {
bot.commands.set(pull.config.name, pull);
pull.config.aliases.forEach(alias => {
bot.aliases.set(alias, pull.config.name)
});
}
}
const commandsFolder = fs.readdirSync('./commands').filter(file => file.endsWith('.js'));
for (const file of commandsFolder) {
const commandFile = require(`./commands/${file}`);
const command = file.split(".")[0];
bot.commands.set(command, commandFile);
commandFile.config.aliases.forEach(alias => {
bot.aliases.set(alias, command);
});
};

//Slash command handler
let slashCommands = [];
const slashCommandsFolder = fs.readdirSync('./slashes').filter(file => file.endsWith('.js'));
for (const file of slashCommandsFolder) {
const commandFile = require(`./slashes/${file}`);
const slashCommand = file.split(".")[0];
bot.slashes.set(slashCommand, commandFile);
slashCommands.push(commandFile.data.toJSON());
};

bot.once('ready', async (bot) => {
const rest = new REST({ version: '9' }).setToken(bot.token);

try {
await rest.put(
Routes.applicationCommands(bot.user.id),
{ body: slashCommands },
);
} catch (err) {
console.log(err);
};
});

//Bot login
Expand Down
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "minecraft-bot",
"version": "1.4.2",
"version": "1.5.0",
"description": "Discord minecraft bot, with which you can check your minecraft server status (online players, version, online status etc.)",
"main": "index.js",
"scripts": {
Expand Down Expand Up @@ -32,7 +32,10 @@
"npm": "8.1.0"
},
"dependencies": {
"@discordjs/builders": "^0.12.0",
"@discordjs/rest": "^0.3.0",
"chalk": "^4.1.2",
"discord-api-types": "^0.26.1",
"discord.js": "^13.6.0",
"fs": "^0.0.1-security",
"math": "^0.0.3",
Expand Down
41 changes: 41 additions & 0 deletions slashes/ip.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
const { SlashCommandBuilder } = require('@discordjs/builders');
const Discord = require('discord.js');

module.exports = {
data: new SlashCommandBuilder()
.setName('ip') //Name of command - RENAME THE FILE TOO!!!
.setDescription(`Sends the IP address of server`) //Description of command - you can change it :)
};

module.exports.run = async (bot, interaction) => {
const { server, config, text } = bot
let icon = server.icon ? server.icon : interaction.guild.icon

if(text.ip.title === "" || text.ip.description === "") {
const ipEmbed = new Discord.MessageEmbed()
.setAuthor({ name: config.server.name ? config.server.name : interaction.guild.name, iconURL: icon })
.setTitle("IP address:")
.setDescription(`\`${server.ip}\`:\`${server.port}\``)
.setColor(config.embeds.color);
interaction.reply({ embeds: [ipEmbed] });
} else {
text.ip.title = text.ip.title.replace('{serverIp}', server.ip)
text.ip.title = text.ip.title.replace('{serverPort}', server.port)
text.ip.title = text.ip.title.replace('{serverName}', config.server.name ? config.server.name : interaction.guild.name)
text.ip.title = text.ip.title.replace('{voteLink}', config.server.vote)
text.ip.title = text.ip.title.replace('{serverType}', config.server.type.charAt(0).toUpperCase() + config.server.type.slice(1))

text.ip.description = text.ip.description.replace('{serverIp}', server.ip)
text.ip.description = text.ip.description.replace('{serverPort}', server.port)
text.ip.description = text.ip.description.replace('{serverName}', config.server.name ? config.server.name : interaction.guild.name)
text.ip.description = text.ip.description.replace('{voteLink}', config.server.vote)
text.ip.description = text.ip.description.replace('{serverType}', config.server.type.charAt(0).toUpperCase() + config.server.type.slice(1))

const ipEmbed = new Discord.MessageEmbed()
.setAuthor({ name: config.server.name ? config.server.name : interaction.guild.name, iconURL: icon })
.setTitle(text.ip.title)
.setDescription(text.ip.description)
.setColor(config.embeds.color);
interaction.reply({ embeds: [ipEmbed] });
}
};
95 changes: 95 additions & 0 deletions slashes/list.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
const { SlashCommandBuilder } = require('@discordjs/builders');
const util = require('minecraft-server-util');
const Discord = require('discord.js');
const c = require('chalk')

module.exports = {
data: new SlashCommandBuilder()
.setName('list') //Name of command - RENAME THE FILE TOO!!!
.setDescription('Sends the actual list of players online') //Description of command - you can change it :)
};

module.exports.run = async (bot, interaction) => {
const { server, config, text } = bot,
warn = c.keyword('yellow').bold,
warns = config.settings.warns

if(!server.work) return

let
ip1 = server.ip,
port1 = server.port,
icon = server.icon ? server.icon : interaction.guild.icon

if(server.type === 'java') {
util.status(ip1, port1)
.then((result) => {
if (text.list.title === "" || text.list.description === "" || text.list.listFormat === "") {
const trueList = result.players.sample ? "\n\`\`\`" + result.players.sample.map(p => ` ${p.name} `).join('\r\n') + "\`\`\`":""

const serverEmbed = new Discord.MessageEmbed()
.setAuthor({ name: config.server.name ? config.server.name : interaction.guild.name, iconURL: icon })
.setTitle("Online player list:")
.setDescription(`**${result.players.online}**/**${result.players.max}**` + trueList)
.setColor(config.embeds.color)
interaction.reply({ embeds: [serverEmbed] });
} else {
text.list.title = text.list.title.replace('{serverIp}', server.ip)
text.list.title = text.list.title.replace('{serverPort}', server.port)
text.list.title = text.list.title.replace('{serverName}', config.server.name ? config.server.name : interaction.guild.name)
text.list.title = text.list.title.replace('{voteLink}', config.server.vote)
text.list.title = text.list.title.replace('{serverType}', config.server.type.charAt(0).toUpperCase() + config.server.type.slice(1))
text.list.title = text.list.title.replace('{playersOnline}', result.players.online)
text.list.title = text.list.title.replace('{playersMax}', result.players.max)

text.list.description = text.list.description.replace('{serverIp}', server.ip)
text.list.description = text.list.description.replace('{serverPort}', server.port)
text.list.description = text.list.description.replace('{serverName}', config.server.name ? config.server.name : interaction.guild.name)
text.list.description = text.list.description.replace('{voteLink}', config.server.vote)
text.list.description = text.list.description.replace('{serverType}', config.server.type.charAt(0).toUpperCase() + config.server.type.slice(1))
text.list.description = text.list.description.replace('{playersOnline}', result.players.online)
text.list.description = text.list.description.replace('{playersMax}', result.players.max)

if (result.players.sample) {
var trueList = text.list.listFormat.replace('{playersList}', result.players.sample.map(p => ` ${p.name} `).join('\r\n'))
}

const serverEmbed = new Discord.MessageEmbed()
.setAuthor({ name: config.server.name ? config.server.name : interaction.guild.name, iconURL: icon })
.setTitle(text.list.title)
.setDescription(text.list.description + (trueList ? `\n${trueList}` : ""))
.setColor(config.embeds.color)
interaction.reply({ embeds: [serverEmbed] });
}
})
.catch((error) => {
if (text.list.title === "" || text.list.description === "" || text.list.listFormat === "") {
const errorEmbed = new Discord.MessageEmbed()
.setAuthor({ name: config.server.name ? config.server.name : interaction.guild.name, iconURL: icon })
.setTitle("Online player list:")
.setDescription(`:x: **OFFLINE**\n\n:information_source: \`${server.ip}\`:\`${server.port}\``)
.setColor(config.embeds.error)
interaction.reply({ embeds: [errorEmbed] });
} else {
text.list.title = text.list.title.replace('{serverIp}', server.ip)
text.list.title = text.list.title.replace('{serverPort}', server.port)
text.list.title = text.list.title.replace('{serverName}', config.server.name ? config.server.name : interaction.guild.name)
text.list.title = text.list.title.replace('{voteLink}', config.server.vote)
text.list.title = text.list.title.replace('{serverType}', config.server.type.charAt(0).toUpperCase() + config.server.type.slice(1))

const errorEmbed = new Discord.MessageEmbed()
.setAuthor({ name: config.server.name ? config.server.name : interaction.guild.name, iconURL: icon })
.setTitle("Online player list:")
.setDescription(`:x: **OFFLINE**\n\n:information_source: \`${server.ip}\`:\`${server.port}\``)
.setColor(config.embeds.error)
interaction.reply({ embeds: [errorEmbed] });
}

if (warns) console.log(warn(`Error when using command ${module.exports.config.name}! Error:\n`) + error)
});
} else {
//Doesn't work for bedrock edition, sorry.
interaction.reply({ content: 'Sorry, but this function is not working for Bedrock servers.' })
}

};
Loading

0 comments on commit c4501d8

Please sign in to comment.