From 0d5a3c5b53e40e49c0d8517c1343cd10a425025a Mon Sep 17 00:00:00 2001 From: Braeden Sowinski Date: Thu, 26 Oct 2023 16:01:40 -0700 Subject: [PATCH] feature/fix disableBaseDamage command + move to /server command --- commands/admin.js | 129 +---------------------------------- commands/server.js | 165 +++++++++++++++++++++++++++++++++++++++++++++ events/ready.js | 2 +- package.json | 2 +- src/DayzRBot.js | 21 +++++- util/NitradoAPI.js | 38 ++++++++--- 6 files changed, 217 insertions(+), 140 deletions(-) create mode 100644 commands/server.js diff --git a/commands/admin.js b/commands/admin.js index 8f1899c..65df155 100644 --- a/commands/admin.js +++ b/commands/admin.js @@ -1,7 +1,6 @@ const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, StringSelectMenuBuilder } = require('discord.js'); const CommandOptions = require('../util/CommandOptionTypes').CommandOptionTypes; const bitfieldCalculator = require('discord-bitfield-calculator'); -const { BanPlayer, UnbanPlayer, RestartServer, CheckServerStatus, DisableBaseDamage } = require('../util/NitradoAPI'); const { Armbands } = require('../database/armbands.js'); const { createUser, addUser } = require('../database/user') @@ -70,31 +69,8 @@ module.exports = { type: CommandOptions.String, required: true, }] - }, { - name: "ban-player", - description: "Ban a player from the DayZ server", - value: "ban-player", - type: CommandOptions.SubCommand, - options: [{ - name: "gamertag", - description: "gamertag of the player to ban.", - value: "gamertag", - type: CommandOptions.String, - required: true, - }] - }, { - name: "unban-player", - description: "Unban a player from the DayZ server", - value: "unban-player", - type: CommandOptions.SubCommand, - options: [{ - name: "gamertag", - description: "gamertag of the player to unban.", - value: "gamertag", - type: CommandOptions.String, - required: true, - }] - }, { + }, + { name: "add-money", description: "Add money to user", value: "add", @@ -139,32 +115,9 @@ module.exports = { required: true, }, ] - }, { - name: "restart", - description: "Restart the DayZ Server", - value: "restart", - type: CommandOptions.SubCommand, - }, { - name: "auto-restart", - description: "Enable/Disable periodic server checks and restart if stopped.", - value: "auto-restart", - type: CommandOptions.SubCommand, - }, { - name: "disable-base-damage", - description: "Disable/Enable base damage", - value: "disable-base-damage", - type: CommandOptions.SubCommand, - options: [{ - name: "preference", - description: "DisableBaseDamage Preference", - value: true, - type: CommandOptions.Boolean, - required: true, - }] }], SlashCommand: { /** - * * @param {require("../structures/DayzRBot")} client * @param {import("discord.js").Message} message * @param {string[]} args @@ -362,42 +315,6 @@ module.exports = { return interaction.send({ embeds: [clearedBounty] }); - } else if (args[0].name == 'ban-player') { - - let data = await BanPlayer(client, args[0].options[0].value); - - if (data == 1) { - let failed = new EmbedBuilder() - .setColor(client.config.Colors.Red) - .setDescription(`Failed to ban **${args[0].options[0].value}**. Check internal logs for an error.`); - - return interaciton.send({ embeds: [failed] }); - } - - let banned = new EmbedBuilder() - .setColor(client.config.Colors.Default) - .setDescription(`Successfully **banned** **${args[0].options[0].value}** from the DayZ Server`); - - return interaction.send({ embeds: [banned] }); - - } else if (args[0].name == 'unban-player') { - - let data = UnbanPlayer(client, args[0].options[0].value); - - if (data == 1) { - let failed = new EmbedBuilder() - .setColor(client.config.Colors.Red) - .setDescription(`Failed to ban **${args[0].options[0].value}**. Check internal logs for an error.`); - - return interaction.send({ embeds: [failed] }); - } - - let banned = new EmbedBuilder() - .setColor(client.config.Colors.Default) - .setDescription(`Successfully **unbanned** **${args[0].options[0].value}** from the DayZ Server`); - - return interaction.send({ embeds: [banned] }); - } else if (args[0].name == 'add-money' || args[0].name == 'remove-money') { const targetUserID = args[0].options[1].value; @@ -428,48 +345,6 @@ module.exports = { return interaction.send({ embeds: [successEmbed] }); - } else if (args[0].name == "restart") { - // Write optional "restart_message" to set in the Nitrado server logs and send a notice "message" to your server community. - restart_message = 'Server being restarted by an admin.'; - message = 'The server was restarted by an admin!'; - - RestartServer(client, restart_message, message); - return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Yellow).setDescription('The server will restart shortly.')], flags: (1 << 6) }); - - } else if (args[0].name == "auto-restart") { - msg = 'Auto server restart periodic check enabled.'; - pref = 0; - - // Enable/Disable a 10min periodic server status check. - if (!client.arIntervalId) { - client.arIntervalId = setInterval(CheckServerStatus, client.arInterval, client); - client.log('Enabled and starting periodic Nitrado server status check.'); - pref = 1; - } else { - msg = 'Auto server restart periodic check disabled.' - clearInterval(client.arIntervalId); - client.arIntervalId = 0; - client.log('Disabled periodic Nitrado server status check.'); - } - - // Update DB preference - client.dbo.collection("guilds").updateOne({ "server.serverID": GuildDB.serverID }, { - $set: { - "server.autoRestart": pref - } - }, function (err, res) { - if (err) return client.sendInternalError(interaction, err); - }); - - return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Yellow).setDescription(msg)], flags: (1 << 6) }); - } else if (args[0].name == 'disable-base-damage') { - return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Green).setDescription('This command is disabled as it is currently in development.')] }); - const preference = args[0].options[0].value; - - const toggle = await DisableBaseDamage(client, preference); - if (toggle == 1) return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Red).setDescription('Failed to update ` disableBaseDamage `, try again later.')] }); - - return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Green).setDescription(`Successfully updated \` disableBaseDamage \` to ${preference}.\nRestart the DayZ server to apply these changes.`)] }); } } }, diff --git a/commands/server.js b/commands/server.js new file mode 100644 index 0000000..cc43e7e --- /dev/null +++ b/commands/server.js @@ -0,0 +1,165 @@ +const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, StringSelectMenuBuilder } = require('discord.js'); +const CommandOptions = require('../util/CommandOptionTypes').CommandOptionTypes; +const bitfieldCalculator = require('discord-bitfield-calculator'); +const { BanPlayer, UnbanPlayer, RestartServer, CheckServerStatus, DisableBaseDamage } = require('../util/NitradoAPI'); + +module.exports = { + name: "server", + debug: false, + global: false, + description: "DayZ Server Administrative Commands", + usage: "[command] [options]", + permissions: { + channel: ["VIEW_CHANNEL", "SEND_MESSAGES", "EMBED_LINKS"], + member: [], + }, + options: [ + { + name: "ban-player", + description: "Ban a player from the DayZ server", + value: "ban-player", + type: CommandOptions.SubCommand, + options: [{ + name: "gamertag", + description: "gamertag of the player to ban.", + value: "gamertag", + type: CommandOptions.String, + required: true, + }] + }, { + name: "unban-player", + description: "Unban a player from the DayZ server", + value: "unban-player", + type: CommandOptions.SubCommand, + options: [{ + name: "gamertag", + description: "gamertag of the player to unban.", + value: "gamertag", + type: CommandOptions.String, + required: true, + }] + }, + { + name: "restart", + description: "Restart the DayZ Server", + value: "restart", + type: CommandOptions.SubCommand, + }, { + name: "auto-restart", + description: "Enable/Disable periodic server checks and restart if stopped.", + value: "auto-restart", + type: CommandOptions.SubCommand, + }, { + name: "disable-base-damage", + description: "Disable/Enable base damage", + value: "disable-base-damage", + type: CommandOptions.SubCommand, + options: [{ + name: "preference", + description: "DisableBaseDamage Preference", + value: true, + type: CommandOptions.Boolean, + required: true, + }] + }], + SlashCommand: { + /** + * + * @param {require("../structures/DayzRBot")} client + * @param {import("discord.js").Message} message + * @param {string[]} args + * @param {*} param3 + */ + run: async (client, interaction, args, { GuildDB }) => { + + const permissions = bitfieldCalculator.permissions(interaction.member.permissions); + let canUseCommand = false; + + if (permissions.includes("MANAGE_GUILD")) canUseCommand = true; + if (GuildDB.hasBotAdmin && interaction.member.roles.filter(e => GuildDB.botAdminRoles.indexOf(e) !== -1).length > 0) canUseCommand = true; + if (!canUseCommand) return interaction.send({ content: 'You don\'t have the permissions to use this command.' }); + + if (args[0].name == 'ban-player') { + + let data = await BanPlayer(client, args[0].options[0].value); + + if (data == 1) { + let failed = new EmbedBuilder() + .setColor(client.config.Colors.Red) + .setDescription(`Failed to ban **${args[0].options[0].value}**. Check internal logs for an error.`); + + return interaciton.send({ embeds: [failed] }); + } + + let banned = new EmbedBuilder() + .setColor(client.config.Colors.Default) + .setDescription(`Successfully **banned** **${args[0].options[0].value}** from the DayZ Server`); + + return interaction.send({ embeds: [banned] }); + + } else if (args[0].name == 'unban-player') { + + let data = UnbanPlayer(client, args[0].options[0].value); + + if (data == 1) { + let failed = new EmbedBuilder() + .setColor(client.config.Colors.Red) + .setDescription(`Failed to ban **${args[0].options[0].value}**. Check internal logs for an error.`); + + return interaction.send({ embeds: [failed] }); + } + + let banned = new EmbedBuilder() + .setColor(client.config.Colors.Default) + .setDescription(`Successfully **unbanned** **${args[0].options[0].value}** from the DayZ Server`); + + return interaction.send({ embeds: [banned] }); + + } else if (args[0].name == "restart") { + // Write optional "restart_message" to set in the Nitrado server logs and send a notice "message" to your server community. + restart_message = 'Server being restarted by an admin.'; + message = 'The server was restarted by an admin!'; + + RestartServer(client, restart_message, message); + return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Yellow).setDescription('The server will restart shortly.')], flags: (1 << 6) }); + + } else if (args[0].name == "auto-restart") { + msg = 'Auto server restart periodic check enabled.'; + pref = 0; + + // Enable/Disable a 10min periodic server status check. + if (!client.arIntervalId) { + client.arIntervalId = setInterval(CheckServerStatus, client.arInterval, client); + client.log('Enabled and starting periodic Nitrado server status check.'); + pref = 1; + } else { + msg = 'Auto server restart periodic check disabled.' + clearInterval(client.arIntervalId); + client.arIntervalId = 0; + client.log('Disabled periodic Nitrado server status check.'); + } + + // Update DB preference + client.dbo.collection("guilds").updateOne({ "server.serverID": GuildDB.serverID }, { + $set: { + "server.autoRestart": pref + } + }, function (err, res) { + if (err) return client.sendInternalError(interaction, err); + }); + + return interaction.send({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Yellow).setDescription(msg)], flags: (1 << 6) }); + } else if (args[0].name == 'disable-base-damage') { + const preference = args[0].options[0].value; + await interaction.deferReply({ flags: (1 << 6) }); + + const toggle = await DisableBaseDamage(client, preference); + + if (toggle == 1) return interaction.editReply({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Red).setDescription('Failed to set **disableBaseDamage**, try again later.')], flags: (1 << 6) }); + return interaction.editReply({ embeds: [new EmbedBuilder().setColor(client.config.Colors.Green).setDescription(`Successfully set **disableBaseDamage** to ${preference}.\nRestart the DayZ server to apply these changes.`)], flags: (1 << 6) }); + } + } + }, + + Interactions: {} +} diff --git a/events/ready.js b/events/ready.js index 2f1d9f9..0892534 100644 --- a/events/ready.js +++ b/events/ready.js @@ -8,4 +8,4 @@ module.exports = async (client) => { client.log(`Ready to serve in ${client.channels.cache.size} channels on ${client.guilds.cache.size} servers, for a total of ${client.users.cache.size} users.`) client.RegisterSlashCommands(); setInterval(client.logsUpdateTimer, client.timer, client); -}; \ No newline at end of file +}; diff --git a/package.json b/package.json index b18d17a..39b867d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dayzr-bot", - "version": "11.3.1", + "version": "11.4.0", "description": "A General Purpose Discord Bot for DayZ Nitrado Servers.", "main": "index.js", "nodemonConfig": { diff --git a/src/DayzRBot.js b/src/DayzRBot.js index 05729ff..2826379 100644 --- a/src/DayzRBot.js +++ b/src/DayzRBot.js @@ -77,12 +77,12 @@ class DayzRBot extends Client { this.log(`Interaction - ${command}`); + this.rest = new REST({ version: '10' }).setToken(this.config.Token); + // Easy to send response so ;) interaction.guild = await this.guilds.fetch(interaction.guild_id); interaction.send = async (message) => { - const rest = new REST({ version: '10' }).setToken(this.config.Token); - - return await rest.post(Routes.interactionCallback(interaction.id, interaction.token), { + return await this.rest.post(Routes.interactionCallback(interaction.id, interaction.token), { body: { type: 4, data: message, @@ -90,6 +90,21 @@ class DayzRBot extends Client { }); }; + interaction.deferReply = async (message) => { + return await this.rest.post(Routes.interactionCallback(interaction.id, interaction.token), { + body: { + type: 5, + data: message, + } + }); + }; + + interaction.editReply = async (message) => { + return await this.rest.patch(Routes.webhookMessage(this.application.id, interaction.token), { + body: message, + }); + }; + if (!this.databaseConnected) { let dbFailedEmbed = new EmbedBuilder() .setDescription(`**Internal Error:**\nUh Oh D: Its not you, its me.\nThe bot has failed to connect to the database 5 times!\nContact the Developers\nhttps://discord.gg/YCXhvy9uZw`) diff --git a/util/NitradoAPI.js b/util/NitradoAPI.js index c1f62b1..2a13213 100644 --- a/util/NitradoAPI.js +++ b/util/NitradoAPI.js @@ -101,6 +101,27 @@ const HandlePlayerBan = async (client, gamertag, ban) => { } } +const GetRemoteDir = async (client, dir="") => { + const dirParam = client.exists(dir) ? `?dir=${dir}` : ""; + for (let retries = 0; retries <= maxRetries; retries++) { + try { + const res = await fetch(`https://api.nitrado.net/services/${client.config.Nitrado.ServerID}/gameservers/file_server/list${dirParam}`, { + headers: { + "Authorization": client.config.Nitrado.Auth + } + }).then(response => + response.json().then(data => data) + ).then(res => res); + + return res.data.entries; + } catch (error) { + client.error(`GetRemoteDir: Error connecting to server (${client.config.Nitrado.ServerID}): ${error.message}`); + if (retries == maxRetries) throw new Error(`GetRemoteDir: Error connecting to server (${client.config.Nitrado.ServerID}) after ${maxRetries} retries`) + } + await new Promise(resolve => setTimeout(resolve, retryDelay)); // Delay before retrying + } +} + // Public functions (called externally) module.exports = { @@ -215,18 +236,19 @@ module.exports = { }, DisableBaseDamage: async (client, preference) => { - const settings = await module.exports.FetchServerSettings(client, 'ToggleBaseDamage'); // Fetch server settings + const settings = await module.exports.FetchServerSettings(client, 'DisableBaseDamage'); // Fetch server settings if (settings == 1) return 1; const pref = preference ? '1' : '0'; - const posted = await PostServerSettings(client, "config", "ToggleBaseDamage", pref); + const posted = await PostServerSettings(client, "config", "disableBaseDamage", pref); if (posted == 1) return 1; - const remoteDir = `/games/${client.config.Nitrado.UserID}/ftproot/dayzxb_missions/dayzOffline.chernarusplus`; - const remoteFilename = 'cfggameplay.json'; + const basePath = await GetRemoteDir(client).then(dirs => dirs.filter(dir => dir.type == 'dir')[0].path) + const missionPath = await GetRemoteDir(client, basePath).then(dirs => dirs[0].path) + const cfggameplayPath = `${missionPath}/cfggameplay.json`; - const jsonDir = `./logs/${remoteFilename}`; - await module.exports.DownloadNitradoFile(client, `${remoteDir}/${remoteFilename}`, jsonDir); + const jsonDir = `./logs/cfggameplay.json`; + await module.exports.DownloadNitradoFile(client, cfggameplayPath, jsonDir); let gameplay = JSON.parse(fs.readFileSync(jsonDir)); gameplay.GeneralData.disableBaseDamage = preference; @@ -234,9 +256,9 @@ module.exports = { // write JSON to file fs.writeFileSync(jsonDir, JSON.stringify(gameplay, null, 2)); - const uploaded = await UploadNitradoFile(client, remoteDir, remoteFilename, jsonDir); + const uploaded = await UploadNitradoFile(client, missionPath, 'cfggameplay.json', jsonDir); if (uploaded == 1) return 1; - return 0; + return 0; } }