diff --git a/DiscordBot/commands/Admin/createcustommatchcode.js b/DiscordBot/commands/Admin/createcustommatchcode.js new file mode 100644 index 0000000..c5d089e --- /dev/null +++ b/DiscordBot/commands/Admin/createcustommatchcode.js @@ -0,0 +1,100 @@ +const MMCodes = require("../../../model/mmcodes.js"); +const { MessageEmbed } = require("discord.js"); +const log = require("../../../structs/log.js"); +const config = require('../../../Config/config.json') + +module.exports = { + commandInfo: { + name: "create-custom-match-code", + description: "Create a custom matchmaking code.", + options: [ + { + name: "code", + description: "The matchmaking code you want.", + required: true, + type: 3 + }, + { + name: "ip", + description: "The ip of your gameserver.", + required: true, + type: 3 + }, + { + name: "port", + description: "The port of your gameserver.", + required: true, + type: 4 + } + ] + }, + execute: async (interaction) => { + if (!config.moderators.includes(interaction.user.id)) { + return interaction.reply({ content: "You do not have moderator permissions.", ephemeral: true }); + } + + try { + const code = interaction.options.getString('code'); + const ip = interaction.options.getString('ip'); + const port = interaction.options.getInteger('port'); + + if (code.length > 24) return interaction.reply({ content: "Your code can't be longer than 24 characters.", ephemeral: true }); + if (code.length < 4) return interaction.reply({ content: "Your code has to be at least 4 characters long.", ephemeral: true }); + if (code.includes(" ")) return interaction.reply({ content: "Your code can't contain spaces", ephemeral: true }); + if (/[~`!#$%\^&*+=\-\[\]\\';,/{}|\\":<>\?]/g.test(code)) return interaction.reply({ content: "Your code can't contain any special characters", ephemeral: true }); + + const ipExp = new RegExp("^((25[0-5]|(2[0-4]|1[0-9]|[1-9]|)[0-9])(\.(?!$)|$)){4}$"); + if (!ipExp.test(ip)) return interaction.reply({ content: "You provided an invalid IP address", ephemeral: true }); + + if (port < 1 || port > 65535) { + return interaction.reply({ content: "The port must be a number between 1 and 65535.", ephemeral: true }); + } + + const codeExists = await MMCodes.findOne({ code_lower: code.toLowerCase() }); + if (codeExists) return interaction.reply({ content: "This code already exists", ephemeral: true }); + + const newCode = await MMCodes.create({ + created: new Date(), + code: code, + code_lower: code.toLowerCase(), + ip: ip, + port: port + }); + await newCode.save(); + + const embed = new MessageEmbed() + .setTitle("Successfully Created Custom Game Code!") + .setDescription("Your code has been created. You can now use it to host custom games.") + .setColor("GREEN") + .addFields([ + { + name: "Code", + value: code, + inline: true + }, + { + name: "IP", + value: ip, + inline: true + }, + { + name: "Port", + value: port?.toString(), + inline: true + } + ]) + .setTimestamp() + .setThumbnail("https://i.imgur.com/2RImwlb.png") + .setFooter({ + text: "Reload Backend", + iconURL: "https://i.imgur.com/2RImwlb.png" + }); + + await interaction.reply({ embeds: [embed], ephemeral: true }); + + } catch (error) { + log.error(error); + return interaction.reply({ content: "An error occurred while processing your request.", ephemeral: true }); + } + } +}; \ No newline at end of file diff --git a/DiscordBot/commands/Admin/custommatchcodelist.js b/DiscordBot/commands/Admin/custommatchcodelist.js new file mode 100644 index 0000000..331116a --- /dev/null +++ b/DiscordBot/commands/Admin/custommatchcodelist.js @@ -0,0 +1,48 @@ +const MMCodes = require("../../../model/mmcodes.js"); +const { MessageEmbed } = require("discord.js"); +const log = require("../../../structs/log.js"); +const config = require('../../../Config/config.json') + +module.exports = { + commandInfo: { + name: "custom-match-code-list", + description: "Lists all custom matchmaking codes.", + }, + execute: async (interaction) => { + if (!config.moderators.includes(interaction.user.id)) { + return interaction.reply({ content: "You do not have moderator permissions.", ephemeral: true }); + } + + try { + const codes = await MMCodes.find({}); + + if (codes.length === 0) { + return interaction.reply({ content: "No custom matchmaking codes found.", ephemeral: true }); + } + + const embed = new MessageEmbed() + .setTitle("Custom Matchmaking Codes") + .setDescription("Here is the list of all custom matchmaking codes:") + .setColor("GREEN") + .setTimestamp() + .setThumbnail("https://i.imgur.com/2RImwlb.png") + .setFooter({ + text: "Reload Backend", + iconURL: "https://i.imgur.com/2RImwlb.png" + }); + + codes.forEach(code => { + embed.addFields([ + { name: "Code", value: code.code, inline: true }, + { name: "IP", value: code.ip, inline: true }, + { name: "Port", value: code.port.toString(), inline: true } + ]); + }); + + await interaction.reply({ embeds: [embed], ephemeral: true }); + } catch (error) { + log.error(error); + return interaction.reply({ content: "An error occurred while fetching the codes.", ephemeral: true }); + } + } +}; \ No newline at end of file diff --git a/DiscordBot/index.js b/DiscordBot/index.js index a185bb5..699a43d 100644 --- a/DiscordBot/index.js +++ b/DiscordBot/index.js @@ -6,6 +6,8 @@ const config = JSON.parse(fs.readFileSync("./Config/config.json").toString()); const log = require("../structs/log.js"); const Users = require("../model/user.js"); +client.commands = new Map(); + client.once("ready", () => { log.bot("Bot is up and running!"); @@ -35,8 +37,6 @@ client.once("ready", () => { } } - let commands = client.application.commands; - const loadCommands = (dir) => { fs.readdirSync(dir).forEach(file => { const filePath = path.join(dir, file); @@ -44,7 +44,8 @@ client.once("ready", () => { loadCommands(filePath); } else if (file.endsWith(".js")) { const command = require(filePath); - commands.create(command.commandInfo); + const normalizedCommandName = command.commandInfo.name.replace(/[^a-zA-Z0-9]/g, "").toLowerCase(); + client.commands.set(normalizedCommandName, command); } }); }; @@ -55,22 +56,20 @@ client.once("ready", () => { client.on("interactionCreate", async interaction => { if (!interaction.isApplicationCommand()) return; - const executeCommand = (dir, commandName) => { - const commandPath = path.join(dir, commandName + ".js"); - if (fs.existsSync(commandPath)) { - require(commandPath).execute(interaction); - return true; - } - const subdirectories = fs.readdirSync(dir).filter(subdir => fs.lstatSync(path.join(dir, subdir)).isDirectory()); - for (const subdir of subdirectories) { - if (executeCommand(path.join(dir, subdir), commandName)) { - return true; - } - } - return false; - }; + const normalizedCommandName = interaction.commandName.replace(/[^a-zA-Z0-9]/g, "").toLowerCase(); + const command = client.commands.get(normalizedCommandName); - executeCommand(path.join(__dirname, "commands"), interaction.commandName); + if (!command) { + log.error(`Command "${interaction.commandName}" not found.`); + return; + } + + try { + await command.execute(interaction); + } catch (error) { + log.error(`Error executing command "${interaction.commandName}": ${error}`); + interaction.reply({ content: "There was an error while executing this command!", ephemeral: true }); + } }); client.on("guildBanAdd", async (ban) => { diff --git a/README.md b/README.md index 9849963..d038060 100644 --- a/README.md +++ b/README.md @@ -82,9 +82,11 @@ Created by [Burlone](https://github.com/burlone0), This is a modded backend, all - `/addall {user}` - Allows you to give a user all cosmetics. Note: This will reset all your lockers to default - `/addvbucks {user} {vbucks}` - Lets you change a users amount of vbucks - `/additem {user} {cosmeticname}` - The name of the cosmetic you want to give +- `/create-custom-match-code {code} {ip} {port}` - Create a custom matchmaking code. - `/ban {targetUsername}` - Ban a user from the backend by their username. - `/createhostaccount` - Creates a host account for Reload Backend. - `/createsac {code} {ingame-username}` - Creates a Support A Creator Code. +- `/custom-match-code-list` - Lists all custom matchmaking codes. - `/delete {username}` - Deletes a users account - `/deletediscord {username}` - Deletes a users account - `/deletesac {username}` - Deletes a Support A Creator Code. diff --git a/model/mmcodes.js b/model/mmcodes.js index f0b6948..f2b6587 100644 --- a/model/mmcodes.js +++ b/model/mmcodes.js @@ -2,12 +2,10 @@ const mongoose = require("mongoose"); const MMCodesSchema = new mongoose.Schema({ created: { type: Date, required: true }, - owner: { type: mongoose.Types.ObjectId, ref: "UserSchema" }, code: { type: String, required: true }, code_lower: { type: String, required: true }, ip: { type: String, required: true }, port: { type: Number, required: true }, - private: { type: Boolean, required: false }, }, { collection: "mmcodes" });