diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 44805eb..ac1d911 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -48,7 +48,7 @@ If you're simply looking to add a new command and not make significant changes t 3. Use the following template to start your command file: ```javascript const { EmbedBuilder } = require('discord.js'); // Not required, but encouraged to use embeds to reply to commands. - const CommandOptions = require('../util/CommandOptionTypes').CommandOptionTypes; // Not required but recommended for clear cmd options. + const ApplicationCommandOptionType = require('../util/CommandOptionTypes').CommandOptionTypes; // Not required but recommended for clear cmd options. module.exports = { name: "new-command", // Insert your command name here, I encourage that you use hyphens `-` to seperate words. @@ -62,7 +62,7 @@ If you're simply looking to add a new command and not make significant changes t name: "cmd_param_1", description: "What this parameter is for", value: "cmd_param_1_default", // Default value of this parameter - type: CommandOptions.String, + type: ApplicationCommandOptionType.String, required: true, } ], @@ -111,7 +111,7 @@ Adding additional interactions to your command? Buttons, Select Menus, etc? You 1. Create an `Interactions` object within your command file. E.g. my new command `/commands/greet.js` will have the following: ```javascript const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, } = require('discord.js'); // Some additional imported definitions for our button. - const CommandOptions = require('../util/CommandOptionTypes').CommandOptionTypes; + const ApplicationCommandOptionType = require('../util/CommandOptionTypes').CommandOptionTypes; module.exports = { name: "greet", @@ -123,7 +123,7 @@ Adding additional interactions to your command? Buttons, Select Menus, etc? You name: "name", description: "Name to greet", value: "name", // Default value of this parameter - type: CommandOptions.String, + type: ApplicationCommandOptionType.String, required: true, }], SlashCommand: { diff --git a/package-lock.json b/package-lock.json index 83c32d3..ce8c685 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,7 @@ "winston": "^3.8.1" }, "devDependencies": { + "@types/concat-stream": "^2.0.3", "@types/node": "^24.5.2", "@typescript-eslint/eslint-plugin": "^8.44.1", "@typescript-eslint/parser": "^8.44.1", @@ -1635,6 +1636,16 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/concat-stream": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/concat-stream/-/concat-stream-2.0.3.tgz", + "integrity": "sha512-3qe4oQAPNwVNwK4C9c8u+VJqv9kez+2MR4qJpoPFfXtgxxif1QbFusvXzK0/Wra2VX07smostI2VMmJNSpZjuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -5813,6 +5824,15 @@ "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", "dev": true }, + "@types/concat-stream": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/concat-stream/-/concat-stream-2.0.3.tgz", + "integrity": "sha512-3qe4oQAPNwVNwK4C9c8u+VJqv9kez+2MR4qJpoPFfXtgxxif1QbFusvXzK0/Wra2VX07smostI2VMmJNSpZjuQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", diff --git a/package.json b/package.json index e1c36af..dc3c988 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "winston": "^3.8.1" }, "devDependencies": { + "@types/concat-stream": "^2.0.3", "@types/node": "^24.5.2", "@typescript-eslint/eslint-plugin": "^8.44.1", "@typescript-eslint/parser": "^8.44.1", diff --git a/src/bot.ts b/src/bot.ts index 4d678df..3062db1 100644 --- a/src/bot.ts +++ b/src/bot.ts @@ -1,5 +1,5 @@ import DayZR from "./DayZRBot"; -import config from "./config/config"; +import { config } from "./config/config"; import { GatewayIntentBits } from "discord.js"; import path from "path"; diff --git a/src/commands/admin.js b/src/commands/admin.js index 03c3a17..7aecee4 100644 --- a/src/commands/admin.js +++ b/src/commands/admin.js @@ -1,5 +1,5 @@ const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, StringSelectMenuBuilder } = require("discord.js"); -const CommandOptions = require("../util/CommandOptionTypes").CommandOptionTypes; +const { ApplicationCommandOptionType } = require("discord.js"); const bitfieldCalculator = require("discord-bitfield-calculator"); const { Armbands } = require("../database/armbands.js"); const { createUser, addUser } = require("../database/user"); @@ -19,55 +19,55 @@ module.exports = { name: "gamertag-link", description: "Link a gamertag for a user", value: "gamertag-link", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "user", description: "User to link gamertag to", value: "user", - type: CommandOptions.User, + type: ApplicationCommandOptionType.User, required: true, }, { name: "gamertag", description: "Gamertag of player", value: "gamertag", - type: CommandOptions.String, + type: ApplicationCommandOptionType.String, required: true, }] }, { name: "gamertag-unlink", description: "Unlink a gamertag for a user", value: "gamertag-unlink", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "user", description: "User to link gamertag to", value: "user", - type: CommandOptions.User, + type: ApplicationCommandOptionType.User, required: true, }] }, { name: "claim-armband", description: "Claim an armband for a faction", value: "claim-armband", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "faction_role", description: "Claim an armband for this faction role.", value: "faction_role", - type: CommandOptions.Role, + type: ApplicationCommandOptionType.Role, required: true, }] }, { name: "bounty-clear", description: "Clear a bounty off a player", value: "bounty-clear", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "gamertag", description: "Gamertag of player", value: "gamertag", - type: CommandOptions.String, + type: ApplicationCommandOptionType.String, required: true, }] }, @@ -75,43 +75,43 @@ module.exports = { name: "money", description: "Add/Remove money to a user", value: "money", - type: CommandOptions.SubCommandGroup, + type: ApplicationCommandOptionType.SubCommandGroup, options: [{ name: "add", description: "Add money to user", value: "add", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "amount", description: "The amount to add to balance", value: "amount", - type: CommandOptions.Float, + type: ApplicationCommandOptionType.Float, min_value: 0.01, required: true, }, { name: "to", description: "User to alter balance", value: "to", - type: CommandOptions.User, + type: ApplicationCommandOptionType.User, required: true, }], }, { name: "remove", description: "Remove money from a user", value: "remove", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "amount", description: "The amount to remove from balance", value: "amount", - type: CommandOptions.Float, + type: ApplicationCommandOptionType.Float, min_value: 0.01, required: true, }, { name: "from", description: "User to alter balance", value: "from", - type: CommandOptions.User, + type: ApplicationCommandOptionType.User, required: true, }] }] diff --git a/src/commands/alarm.js b/src/commands/alarm.js index eb4a0a9..db700fe 100644 --- a/src/commands/alarm.js +++ b/src/commands/alarm.js @@ -1,5 +1,5 @@ const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, StringSelectMenuBuilder } = require("discord.js"); -const CommandOptions = require("../util/CommandOptionTypes").CommandOptionTypes; +const { ApplicationCommandOptionType } = require("discord.js"); const bitfieldCalculator = require("discord-bitfield-calculator"); const generateAlarmMenus = (alarms, customId, placeholder, description) => { @@ -40,13 +40,13 @@ module.exports = { name: "create", description: "Create a new Zone Ping Alarm", value: "create", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [ { name: "x-coord", description: "X Coordinate of the origin", value: "x-coord", - type: CommandOptions.Float, + type: ApplicationCommandOptionType.Float, min_value: 0.01, required: true, }, @@ -54,7 +54,7 @@ module.exports = { name: "y-coord", description: "Y Coordinate of the origin", value: "y-coord", - type: CommandOptions.Float, + type: ApplicationCommandOptionType.Float, min_value: 0.01, required: true, }, @@ -62,7 +62,7 @@ module.exports = { name: "radius", description: "Radius of Alarm", value: "radius", - type: CommandOptions.Float, + type: ApplicationCommandOptionType.Float, min_value: 25.00, required: true, }, @@ -70,14 +70,14 @@ module.exports = { name: "name", description: "Alarm Name", value: "name", - type: CommandOptions.String, + type: ApplicationCommandOptionType.String, required: true, }, { name: "channel", description: "Alarm Channel", value: "channel", - type: CommandOptions.Channel, + type: ApplicationCommandOptionType.Channel, channel_types: [0], // Restrict to text channel required: true, }, @@ -85,21 +85,21 @@ module.exports = { name: "role", description: "Role to Ping on Alarm", value: "role", - type: CommandOptions.Role, + type: ApplicationCommandOptionType.Role, required: true, }, { name: "emp-exempt", description: "Is this Alarm Exempt to EMP Attacks?", value: false, - type: CommandOptions.Boolean, + type: ApplicationCommandOptionType.Boolean, required: false, }, { name: "show-player-coords", description: "Show a players coords when in the radius of the Alarm?", value: true, - type: CommandOptions.Boolean, + type: ApplicationCommandOptionType.Boolean, required: false, } ] @@ -108,18 +108,18 @@ module.exports = { name: "delete", description: "Delete an Alarm", value: "delete", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, }, { name: "add-player", description: "Add player to be ignored list of an Alarm", value: "add-player", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "gamertag", description: "Gamertag of player to ignore", value: "gamertag", - type: CommandOptions.String, + type: ApplicationCommandOptionType.String, required: true, }] }, @@ -127,12 +127,12 @@ module.exports = { name: "remove-player", description: "Remove a player from the ignored list of an Alarm", value: "remove-player", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "gamertag", description: "Gamertag of player to ignore", value: "gamertag", - type: CommandOptions.String, + type: ApplicationCommandOptionType.String, required: true, }] }, @@ -140,24 +140,24 @@ module.exports = { name: "disable", description: "Disable an Alarm", value: "disable", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, }, { name: "enable", description: "Enable an Alarm", value: "enable", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, }, { name: "mute", description: "Mute the role ping of an Alarm", value: "mute", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "toggle", description: "Turn on/off role pings for this alarm", value: false, - type: CommandOptions.Boolean, + type: ApplicationCommandOptionType.Boolean, required: true, }] }, @@ -165,12 +165,12 @@ module.exports = { name: "set-rule", description: "Add a Rule to an Alarm", value: "set-rule", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "rule", description: "Select a rule to add to an Alarm", value: "rule", - type: CommandOptions.String, + type: ApplicationCommandOptionType.String, required: true, choices: [ { name: "Ban on Entry", value: "ban_on_entry" }, @@ -183,18 +183,18 @@ module.exports = { name: "remove-rule", description: "Remove a rule from an Alarm", value: "remove-rule", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, }, { name: "rename", description: "Rename an Alarm", value: "rename", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "name", description: "New Alarm Name", value: "name", - type: CommandOptions.String, + type: ApplicationCommandOptionType.String, required: true, }] }, @@ -202,12 +202,12 @@ module.exports = { name: "move-origin", description: "Move the origin of an Alarm", value: "move-origin", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "x-coord", description: "X Coordinate of the new origin", value: "x-coord", - type: CommandOptions.Float, + type: ApplicationCommandOptionType.Float, min_value: 0.01, required: true, }, @@ -215,7 +215,7 @@ module.exports = { name: "y-coord", description: "Y Coordinate of the new origin", value: "y-coord", - type: CommandOptions.Float, + type: ApplicationCommandOptionType.Float, min_value: 0.01, required: true, }] diff --git a/src/commands/bank.js b/src/commands/bank.js index 9ac075f..0b74e0b 100644 --- a/src/commands/bank.js +++ b/src/commands/bank.js @@ -1,5 +1,5 @@ const { EmbedBuilder } = require("discord.js"); -const CommandOptions = require("../util/CommandOptionTypes").CommandOptionTypes; +const { ApplicationCommandOptionType } = require("discord.js"); const { createUser, addUser } = require("../database/user"); module.exports = { @@ -17,12 +17,12 @@ module.exports = { name: "balance", description: "View your bank balance", value: "balance", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "user", description: "User to view ballance", value: "user", - type: CommandOptions.User, + type: ApplicationCommandOptionType.User, required: false, }] }, @@ -30,20 +30,20 @@ module.exports = { name: "transfer", description: "Transfer money to another user", value: "transfer", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [ { name: "user", description: "User to transfer to", value: "user", - type: CommandOptions.User, + type: ApplicationCommandOptionType.User, required: true, }, { name: "amount", description: "The amount to transfer", value: "amount", - type: CommandOptions.Float, + type: ApplicationCommandOptionType.Float, min_value: 0.01, required: true, }, diff --git a/src/commands/bounty.js b/src/commands/bounty.js index 5d5c40e..098fd5f 100644 --- a/src/commands/bounty.js +++ b/src/commands/bounty.js @@ -1,5 +1,5 @@ const { EmbedBuilder } = require("discord.js"); -const CommandOptions = require("../util/CommandOptionTypes").CommandOptionTypes; +const { ApplicationCommandOptionType } = require("discord.js"); const { createUser, addUser } = require("../database/user"); const { UpdatePlayer } = require("../database/player"); @@ -17,37 +17,37 @@ module.exports = { name: "set", description: "Set a bounty on a player", value: "set", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "gamertag", description: "Gamertag of player for bounty", value: "gamertag", - type: CommandOptions.String, + type: ApplicationCommandOptionType.String, required: true, }, { name: "value", description: "Amount of the bounty", value: "value", - type: CommandOptions.Float, + type: ApplicationCommandOptionType.Float, min_value: 0.01, required: true }, { name: "anonymous", description: "Make this bounty anonymous (does not show your name)", value: false, - type: CommandOptions.Boolean, + type: ApplicationCommandOptionType.Boolean, required: false }] }, { name: "pay", description: "Pay off your bounty", value: "pay", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, }, { name: "view", description: "View all active bounties", value: "view", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, }], SlashCommand: { /** diff --git a/src/commands/claim.js b/src/commands/claim.js index 3cdf364..22cf35d 100644 --- a/src/commands/claim.js +++ b/src/commands/claim.js @@ -1,5 +1,5 @@ const { ActionRowBuilder, EmbedBuilder, ButtonBuilder, ButtonStyle, StringSelectMenuBuilder } = require("discord.js"); -const CommandOptions = require("../util/CommandOptionTypes").CommandOptionTypes; +const { ApplicationCommandOptionType } = require("discord.js"); const { Armbands } = require("../database/armbands.js"); module.exports = { @@ -16,7 +16,7 @@ module.exports = { name: "faction_role", description: "Claim an armband for this faction role", value: "faction_role", - type: CommandOptions.Role, + type: ApplicationCommandOptionType.Role, required: true, }], SlashCommand: { diff --git a/src/commands/compare-rating.js b/src/commands/compare-rating.js index 5c90dbf..8c4d077 100644 --- a/src/commands/compare-rating.js +++ b/src/commands/compare-rating.js @@ -1,5 +1,5 @@ const { EmbedBuilder } = require("discord.js"); -const CommandOptions = require("../util/CommandOptionTypes").CommandOptionTypes; +const { ApplicationCommandOptionType } = require("discord.js"); const { insertPVPstats } = require("../database/player"); module.exports = { @@ -16,12 +16,12 @@ module.exports = { name: "discord", description: "Discord user to lookup stats", value: "discord", - type: CommandOptions.User, + type: ApplicationCommandOptionType.User, required: false, }, { name: "gamertag", description: "Gamertag to lookup stats", - type: CommandOptions.String, + type: ApplicationCommandOptionType.String, required: false, }], SlashCommand: { diff --git a/src/commands/config.js b/src/commands/config.js index 8f70002..f9212a1 100644 --- a/src/commands/config.js +++ b/src/commands/config.js @@ -1,5 +1,5 @@ const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require("discord.js"); -const CommandOptions = require("../util/CommandOptionTypes").CommandOptionTypes; +const { ApplicationCommandOptionType } = require("discord.js"); const bitfieldCalculator = require("discord-bitfield-calculator"); const { getDefaultSettings } = require("../database/guild"); @@ -18,18 +18,18 @@ module.exports = { name: "killfeed", description: "Configure the killfeed", value: "killfeed", - type: CommandOptions.SubCommandGroup, + type: ApplicationCommandOptionType.SubCommandGroup, options: [ { name: "channel", description: "Configure the killfeed channel", value: "channel", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "channel", description: "The channel to configure", value: "channel", - type: CommandOptions.Channel, + type: ApplicationCommandOptionType.Channel, required: true }] }, @@ -37,12 +37,12 @@ module.exports = { name: "show_coords", description: "Show the coordinates of the victim in the killfeed channel.", value: "show_coords", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "configuration", description: "True or False", value: false, - type: CommandOptions.Boolean, + type: ApplicationCommandOptionType.Boolean, required: true, }] }, @@ -50,12 +50,12 @@ module.exports = { name: "show_weapon", description: "Show the image of the weapon in the killfeed", value: "show_weapon", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "configuration", description: "True or False", value: false, - type: CommandOptions.Boolean, + type: ApplicationCommandOptionType.Boolean, required: true, }] } @@ -65,18 +65,18 @@ module.exports = { name: "allowed_channels", description: "Set channels you're allowed to use the bot in", value: "allowed_channels", - type: CommandOptions.SubCommandGroup, + type: ApplicationCommandOptionType.SubCommandGroup, options: [ { name: "add", description: "Add channel", value: "add", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "channel", description: "The channel to configure", value: "channel", - type: CommandOptions.Channel, + type: ApplicationCommandOptionType.Channel, channel_types: [0], // Restrict to text channel required: true, }] @@ -85,12 +85,12 @@ module.exports = { name: "remove", description: "Remove channel", value: "remove", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "channel", description: "The channel to configure", value: "channel", - type: CommandOptions.Channel, + type: ApplicationCommandOptionType.Channel, channel_types: [0], // Restrict to text channel required: true, }] @@ -99,13 +99,13 @@ module.exports = { name: "clear", description: "Clears all configured channels", value: "clear", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, }, { name: "view", description: "View configured allowed channels", value: "view", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, } ] }, @@ -113,13 +113,13 @@ module.exports = { name: "set_channel", description: "Configure a channel", value: "set_channel", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [ { name: "channel_type", description: "Select the channel type", value: "channel_type", - type: CommandOptions.String, + type: ApplicationCommandOptionType.String, choices: [ { name: "Killfeed", value: "killfeedChannel" }, { name: "Admin Logs", value: "connectionLogsChannel" }, { name: "Welcome", value: "welcomeChannel" }, { name: "Online Players", value: "activePlayersChannel" }, @@ -130,7 +130,7 @@ module.exports = { name: "channel", description: "The channel to configure", value: "channel", - type: CommandOptions.Channel, + type: ApplicationCommandOptionType.Channel, channel_types: [0], // Restrict to text channel required: true, }, @@ -140,12 +140,12 @@ module.exports = { name: "linked_gt_role", description: "Role for users with linked gamertags", value: "linked_gt_role", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "role", description: "Role to configure", value: "role", - type: CommandOptions.Role, + type: ApplicationCommandOptionType.Role, required: true, }] }, @@ -153,12 +153,12 @@ module.exports = { name: "member_role", description: "Role for users who join the server", value: "member_role", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "role", description: "Role to configure", value: "role", - type: CommandOptions.Role, + type: ApplicationCommandOptionType.Role, required: true, }] }, @@ -166,18 +166,18 @@ module.exports = { name: "bot_admin_role", description: "Set/remove bot admin role", value: "bot_admin_role", - type: CommandOptions.SubCommandGroup, + type: ApplicationCommandOptionType.SubCommandGroup, options: [ { name: "add", description: "Configure role to be bot admin", value: "add", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "role", description: "Role to confiure", value: "role", - type: CommandOptions.Role, + type: ApplicationCommandOptionType.Role, required: true, }] }, @@ -185,12 +185,12 @@ module.exports = { name: "remove", description: "Remove configured role as bot admin", value: "remove", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "role", description: "Role to remove", value: "role", - type: CommandOptions.Role, + type: ApplicationCommandOptionType.Role, required: true, }] }, @@ -198,7 +198,7 @@ module.exports = { name: "view", description: "View the configured bot admin roles", value: "view", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, } ] }, @@ -206,12 +206,12 @@ module.exports = { name: "admin_ping_role", description: "Admin role to ping in admin logs channel", value: "admin_ping_role", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "role", description: "Role to configure", value: "role", - type: CommandOptions.Role, + type: ApplicationCommandOptionType.Role, required: true, }] }, @@ -219,18 +219,18 @@ module.exports = { name: "exclude", description: "Exclude roles that can be used to claim armbands", value: "exclude", - type: CommandOptions.SubCommandGroup, + type: ApplicationCommandOptionType.SubCommandGroup, options: [ { name: "add", description: "Configure role to be excluded", value: "add", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "role", description: "Role to confiure", value: "role", - type: CommandOptions.Role, + type: ApplicationCommandOptionType.Role, required: true, }] }, @@ -238,12 +238,12 @@ module.exports = { name: "remove", description: "Remove configured role thats excluded", value: "remove", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "role", description: "Role to remove", value: "role", - type: CommandOptions.Role, + type: ApplicationCommandOptionType.Role, required: true, }] }, @@ -251,7 +251,7 @@ module.exports = { name: "view", description: "View the configured excluded roles", value: "view", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, }, ] }, @@ -259,24 +259,24 @@ module.exports = { name: "reset", description: "Restore all settings to default configurations", value: "reset", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, }, { name: "view", description: "View current settings configuration", value: "view", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, }, { name: "starting_balance", description: "Set the starting balance of a new user", value: "starting_balance", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "amount", description: "The amount to set the starting balance", value: "amount", - type: CommandOptions.Float, + type: ApplicationCommandOptionType.Float, min_value: 1.00, required: true, }] @@ -285,12 +285,12 @@ module.exports = { name: "uav-price", description: "Configure the price of a UAV", value: "uav-price", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "amount", description: "The amount to set the UAV price", value: "amount", - type: CommandOptions.Float, + type: ApplicationCommandOptionType.Float, min_value: 0.01, required: true, }] @@ -299,12 +299,12 @@ module.exports = { name: "emp-price", description: "Configure the price of an EMP", value: "emp-price", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "amount", description: "The amount to set the EMP price", value: "amount", - type: CommandOptions.Float, + type: ApplicationCommandOptionType.Float, min_value: 0.01, required: true, }] @@ -313,26 +313,26 @@ module.exports = { name: "income_role", description: "Set/remove roles to recieve income", value: "set_income_role", - type: CommandOptions.SubCommandGroup, + type: ApplicationCommandOptionType.SubCommandGroup, options: [ { name: "set", description: "Set role", value: "set", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [ { name: "role", description: "Role to set", value: "role", - type: CommandOptions.Role, + type: ApplicationCommandOptionType.Role, required: true, }, { name: "amount", description: "The amount to collect", value: 120.00, - type: CommandOptions.Float, + type: ApplicationCommandOptionType.Float, min_value: 0.01, required: true, } @@ -342,12 +342,12 @@ module.exports = { name: "remove", description: "Remove role", value: "remove", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "role", description: "Role to remove", value: "role", - type: CommandOptions.Role, + type: ApplicationCommandOptionType.Role, required: true, }] }, @@ -357,12 +357,12 @@ module.exports = { name: "income_limiter", description: "Change the number of hours to wait before collecting next income", value: "income_limiter", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "hours", description: "Number of hours till income can be collected", value: 168.00, // 1 week - type: CommandOptions.Float, + type: ApplicationCommandOptionType.Float, min_value: 1.00, required: true, }] @@ -371,12 +371,12 @@ module.exports = { name: "combat-log-timer", description: "Adjust number of minutes to detect combat logs (0 disables combat log)", value: "combat-log-timer", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "minutes", description: "Minutes to qualify combat log", value: 5, - type: CommandOptions.Integer, + type: ApplicationCommandOptionType.Integer, min_value: 0, }] }, @@ -384,12 +384,12 @@ module.exports = { name: "toggle-uav-purchase", description: "Allow/Disallow UAV purchases", value: "toggle-uav-purchase", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "configuration", description: "True or False", value: false, - type: CommandOptions.Boolean, + type: ApplicationCommandOptionType.Boolean, required: true, }] }, @@ -397,12 +397,12 @@ module.exports = { name: "toggle-emp-purchase", description: "Allow/Disallow EMP purchases", value: "toggle-uav-purchase", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "configuration", description: "True or False", value: false, - type: CommandOptions.Boolean, + type: ApplicationCommandOptionType.Boolean, required: true, }] }, @@ -410,12 +410,12 @@ module.exports = { name: "welcome_message_server_name", description: "Configure the server name in the welcome message", value: "welcome_message_server_name", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "name", description: "Server name to include in welcome message", value: "name", - type: CommandOptions.String, + type: ApplicationCommandOptionType.String, required: true, }] } diff --git a/src/commands/event.js b/src/commands/event.js index bdfc70c..eb02008 100644 --- a/src/commands/event.js +++ b/src/commands/event.js @@ -1,5 +1,5 @@ const { EmbedBuilder, ActionRowBuilder, StringSelectMenuBuilder } = require("discord.js"); -const CommandOptions = require("../util/CommandOptionTypes").CommandOptionTypes; +const { ApplicationCommandOptionType } = require("discord.js"); const bitfieldCalculator = require("discord-bitfield-calculator"); module.exports = { @@ -16,19 +16,19 @@ module.exports = { name: "player-track", description: "Track a player and announce location", value: "player-track", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "gamertag", description: "Gamertag of player", value: "gamertag", - type: CommandOptions.String, + type: ApplicationCommandOptionType.String, required: true, }, { name: "time", description: "Duration of tracking", value: "time", - type: CommandOptions.Integer, + type: ApplicationCommandOptionType.Integer, required: true, choices: [ { name: "10-minutes", value: 10 }, { name: "15-minutes", value: 15 }, { name: "20-minutes", value: 20 }, { name: "25-minutes", value: 25 }, @@ -39,28 +39,28 @@ module.exports = { name: "event-name", description: "Name of the event", value: "event-name", - type: CommandOptions.String, + type: ApplicationCommandOptionType.String, required: true, }, { name: "channel", description: "Channel to post tracking data", value: "channel", - type: CommandOptions.Channel, + type: ApplicationCommandOptionType.Channel, channel_types: [0], // Restrict to text channel required: true, }, { name: "role", description: "Optional role to ping", value: "role", - type: CommandOptions.Role, + type: ApplicationCommandOptionType.Role, required: false, }] }, { name: "delete", description: "Delete an active event", value: "delete", - type: CommandOptions.SubCommand + type: ApplicationCommandOptionType.SubCommand }], SlashCommand: { /** diff --git a/src/commands/factions.js b/src/commands/factions.js index 6b803e5..c8b7b86 100644 --- a/src/commands/factions.js +++ b/src/commands/factions.js @@ -1,5 +1,5 @@ const { EmbedBuilder } = require("discord.js"); -const CommandOptions = require("../util/CommandOptionTypes").CommandOptionTypes; +const { ApplicationCommandOptionType } = require("discord.js"); const { Armbands } = require("../database/armbands.js"); module.exports = { @@ -16,7 +16,7 @@ module.exports = { name: "faction_role", description: "View a specific faction's armband by role", value: "faction_role", - type: CommandOptions.Role, + type: ApplicationCommandOptionType.Role, required: false, }], SlashCommand: { diff --git a/src/commands/gamertag-link.js b/src/commands/gamertag-link.js index 32b9c45..9753995 100644 --- a/src/commands/gamertag-link.js +++ b/src/commands/gamertag-link.js @@ -1,5 +1,5 @@ const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require("discord.js"); -const CommandOptions = require("../util/CommandOptionTypes").CommandOptionTypes; +const { ApplicationCommandOptionType } = require("discord.js"); const { UpdatePlayer } = require("../database/player"); module.exports = { @@ -16,7 +16,7 @@ module.exports = { name: "gamertag", description: "Gamertag of player", value: "gamertag", - type: CommandOptions.String, + type: ApplicationCommandOptionType.String, required: true, }], SlashCommand: { diff --git a/src/commands/help.js b/src/commands/help.js index a2339bd..8d39915 100644 --- a/src/commands/help.js +++ b/src/commands/help.js @@ -1,5 +1,5 @@ const { EmbedBuilder } = require("discord.js"); -const CommandOptions = require("../util/CommandOptionTypes").CommandOptionTypes; +const { ApplicationCommandOptionType } = require("discord.js"); const pack = require("../../package"); // Project root package.json module.exports = { @@ -17,12 +17,12 @@ module.exports = { name: "commands", description: "List all commands", value: "commands", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "command", description: "Get information on a specific command", value: "command", - type: CommandOptions.String, + type: ApplicationCommandOptionType.String, required: false, }] }, @@ -30,19 +30,19 @@ module.exports = { name: "support", description: "Get support for Application", value: "support", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, }, { name: "credits", description: "DayZ.R Bot Credits", value: "credits", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, }, { name: "stats", description: "Current Bot Statistics", value: "stats", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, } ], SlashCommand: { diff --git a/src/commands/leaderboard.js b/src/commands/leaderboard.js index 23af4fe..0d60417 100644 --- a/src/commands/leaderboard.js +++ b/src/commands/leaderboard.js @@ -1,5 +1,5 @@ const { EmbedBuilder } = require("discord.js"); -const CommandOptions = require("../util/CommandOptionTypes").CommandOptionTypes; +const { ApplicationCommandOptionType } = require("discord.js"); module.exports = { name: "leaderboard", @@ -15,7 +15,7 @@ module.exports = { name: "category", description: "Leaderboard Category", value: "category", - type: CommandOptions.String, + type: ApplicationCommandOptionType.String, required: true, choices: [ { name: "Money", value: "money" }, @@ -38,7 +38,7 @@ module.exports = { name: "limit", description: "Leaderboard limit", value: "limit", - type: CommandOptions.Integer, + type: ApplicationCommandOptionType.Integer, min_value: 1, max_value: 25, required: true, diff --git a/src/commands/lookup.js b/src/commands/lookup.js index ea13237..f79f21d 100644 --- a/src/commands/lookup.js +++ b/src/commands/lookup.js @@ -1,5 +1,5 @@ const { EmbedBuilder } = require("discord.js"); -const CommandOptions = require("../util/CommandOptionTypes").CommandOptionTypes; +const { ApplicationCommandOptionType } = require("discord.js"); module.exports = { name: "lookup", @@ -15,24 +15,24 @@ module.exports = { name: "discord", description: "Find a Discord user from a Gamertag", value: "discord", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "gamertag", description: "Gamertag of player", value: "gamertag", - type: CommandOptions.String, + type: ApplicationCommandOptionType.String, required: true, }] }, { name: "gamertag", description: "Find a Gamertag from a Discord user", value: "gamertag", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "user", description: "Discord User", value: "user", - type: CommandOptions.User, + type: ApplicationCommandOptionType.User, required: true, }] }], diff --git a/src/commands/player-stats.js b/src/commands/player-stats.js index 69288cb..c0a1119 100644 --- a/src/commands/player-stats.js +++ b/src/commands/player-stats.js @@ -1,5 +1,5 @@ const { EmbedBuilder } = require("discord.js"); -const CommandOptions = require("../util/CommandOptionTypes").CommandOptionTypes; +const { ApplicationCommandOptionType } = require("discord.js"); const { insertPVPstats } = require("../database/player"); module.exports = { @@ -16,7 +16,7 @@ module.exports = { name: "category", description: "Leaderboard Category", value: "category", - type: CommandOptions.String, + type: ApplicationCommandOptionType.String, required: true, choices: [ { name: "Money", value: "money" }, @@ -39,12 +39,12 @@ module.exports = { name: "discord", description: "discord user to lookup stats", value: "discord", - type: CommandOptions.User, + type: ApplicationCommandOptionType.User, required: false, }, { name: "gamertag", description: "gamertag to lookup stats", - type: CommandOptions.String, + type: ApplicationCommandOptionType.String, required: false, }], SlashCommand: { diff --git a/src/commands/purchase-emp.js b/src/commands/purchase-emp.js index 722999a..319292f 100644 --- a/src/commands/purchase-emp.js +++ b/src/commands/purchase-emp.js @@ -1,6 +1,6 @@ const { EmbedBuilder, ActionRowBuilder, StringSelectMenuBuilder } = require("discord.js"); const { createUser, addUser } = require("../database/user"); -const CommandOptions = require("../util/CommandOptionTypes").CommandOptionTypes; +const { ApplicationCommandOptionType } = require("discord.js"); module.exports = { name: "purchase-emp", @@ -16,7 +16,7 @@ module.exports = { name: "duration", description: "Select the duration of the emp (30 or 60 minutes)", value: "duration", - type: CommandOptions.Integer, + type: ApplicationCommandOptionType.Integer, required: true, choices: [ { name: "30 Minutes", value: 30 }, diff --git a/src/commands/purchase-uav.js b/src/commands/purchase-uav.js index d6587ab..bb5c17f 100644 --- a/src/commands/purchase-uav.js +++ b/src/commands/purchase-uav.js @@ -1,5 +1,5 @@ const { EmbedBuilder } = require("discord.js"); -const CommandOptions = require("../util/CommandOptionTypes").CommandOptionTypes; +const { ApplicationCommandOptionType } = require("discord.js"); const { createUser, addUser } = require("../database/user") module.exports = { @@ -17,7 +17,7 @@ module.exports = { name: "x-coord", description: "X Coordinate of the origin", value: "x-coord", - type: CommandOptions.Float, + type: ApplicationCommandOptionType.Float, min_value: 0.01, required: true, }, @@ -25,7 +25,7 @@ module.exports = { name: "y-coord", description: "Y Coordinate of the origin", value: "y-coord", - type: CommandOptions.Float, + type: ApplicationCommandOptionType.Float, min_value: 0.01, required: true, }, diff --git a/src/commands/reset.js b/src/commands/reset.js index a93b743..dc5a1c4 100644 --- a/src/commands/reset.js +++ b/src/commands/reset.js @@ -1,5 +1,5 @@ const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require("discord.js"); -const CommandOptions = require("../util/CommandOptionTypes").CommandOptionTypes; +const { ApplicationCommandOptionType } = require("discord.js"); const { addUser } = require("../database/user"); const bitfieldCalculator = require("discord-bitfield-calculator"); @@ -17,7 +17,7 @@ module.exports = { name: "user", description: "User to reset", value: "user", - type: CommandOptions.User, + type: ApplicationCommandOptionType.User, required: true, }], SlashCommand: { diff --git a/src/commands/server.js b/src/commands/server.js index 328b570..d42e774 100644 --- a/src/commands/server.js +++ b/src/commands/server.js @@ -1,5 +1,5 @@ const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, ModalBuilder, TextInputBuilder, TextInputStyle } = require("discord.js"); -const CommandOptions = require("../util/CommandOptionTypes").CommandOptionTypes; +const { ApplicationCommandOptionType } = require("discord.js"); const bitfieldCalculator = require("discord-bitfield-calculator"); const { BanPlayer, UnbanPlayer, RestartServer, CheckServerStatus, DisableBaseDamage, DisableContainerDamage, NitradoCredentialStatus } = require("../util/NitradoAPI"); const { encrypt, decrypt } = require("../util/Cryptic"); @@ -18,48 +18,48 @@ module.exports = { name: "initialize", description: "Connect your Nitrado server to the bot", value: "initialize", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, }, { name: "disconnect", description: "Delete your Nitrado server from the bot database", value: "disconnect", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, }, { name: "credentials-status", description: "Check the status of your Nitrado Credentials", value: "credentials-status", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, }, { name: "retry-credentials", description: "If your credentials are marked as FAILED, try retreiving Nitrado logs again.", value: "retry-credentials", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, }, { name: "ban-player", description: "Ban a player from the DayZ server", value: "ban-player", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "gamertag", description: "gamertag of the player to ban.", value: "gamertag", - type: CommandOptions.String, + type: ApplicationCommandOptionType.String, required: true, }] }, { name: "unban-player", description: "Unban a player from the DayZ server", value: "unban-player", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "gamertag", description: "gamertag of the player to unban.", value: "gamertag", - type: CommandOptions.String, + type: ApplicationCommandOptionType.String, required: true, }] }, @@ -67,34 +67,34 @@ module.exports = { name: "restart", description: "Restart the DayZ Server", value: "restart", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, }, { name: "auto-restart", description: "Enable/Disable periodic server checks and restart if stopped", value: "auto-restart", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, }, { name: "disable-base-damage", description: "Disable/Enable base damage", value: "disable-base-damage", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "preference", description: "DisableBaseDamage Preference", value: true, - type: CommandOptions.Boolean, + type: ApplicationCommandOptionType.Boolean, required: true, }] }, { name: "disable-container-damage", description: "Disable/Enable container damage", value: "disable-container-damage", - type: CommandOptions.SubCommand, + type: ApplicationCommandOptionType.SubCommand, options: [{ name: "preference", description: "disableContainerDamage Preference", value: true, - type: CommandOptions.Boolean, + type: ApplicationCommandOptionType.Boolean, required: true, }] }], diff --git a/src/commands/weapon-stats.js b/src/commands/weapon-stats.js index d63a126..24dcdbb 100644 --- a/src/commands/weapon-stats.js +++ b/src/commands/weapon-stats.js @@ -1,5 +1,5 @@ const { EmbedBuilder, ActionRowBuilder, StringSelectMenuBuilder } = require("discord.js"); -const CommandOptions = require("../util/CommandOptionTypes").CommandOptionTypes; +const { ApplicationCommandOptionType } = require("discord.js"); const { weapons } = require("../database/weapons"); const { insertPVPstats, createWeaponStats } = require("../database/player"); @@ -17,7 +17,7 @@ module.exports = { name: "category", description: "Weapon category", value: "category", - type: CommandOptions.String, + type: ApplicationCommandOptionType.String, required: true, choices: [ { name: "Handguns", value: "handguns" }, @@ -36,12 +36,12 @@ module.exports = { name: "discord", description: "Discord user to lookup stats", value: "discord", - type: CommandOptions.User, + type: ApplicationCommandOptionType.User, required: false, }, { name: "gamertag", description: "Gamertag to lookup stats", - type: CommandOptions.String, + type: ApplicationCommandOptionType.String, required: false, }], SlashCommand: { diff --git a/src/config/config.js b/src/config/config.js deleted file mode 100644 index 1820d55..0000000 --- a/src/config/config.js +++ /dev/null @@ -1,47 +0,0 @@ -const version = require("../../package.json").version; -require("dotenv").config(); - -const PresenceTypes = { - Playing: 0, - Streaming: 1, - Listening: 2, - Watching: 3, - Custom: 4, - Competing: 5, -}; - -const PresenceStatus = { - Online: "online", - Offline: "offline", - Idle: "idle", - DoNotDisturb: "dnd", -}; - -module.exports = { - Dev: process.env.Dev || "DEV.", - Version: version, // (major).(minor).(patch) - Admins: ["362791661274660874", "329371697570381824"], // Admins of the bot - SupportServer: "https://discord.gg/KVFJCvvFtK", // Support Server Link - Token: process.env.token || "", //Discord Bot Token - SecretKey: process.env.key || "01234567891", - SecretIv: process.env.iv || "9876543210", - EncryptionMethod: process.env.encryptionMethod || "aes-256-cbc", - Scopes: ["identify", "guilds", "applications.commands"], //Discord OAuth2 Scopes - IconURL: "https://cdn.discordapp.com/app-icons/1049045393415098450/f8e7f76ac9e843360b989c796fc21990.png?size=256", - AvatarData: "data:image/png;base64,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", - Colors: { - Default: "#8a7c72", - DarkRed: "#ba0f0f", - Red: "#f55c5c", - Green: "#32a852", - Yellow: "#ffb01f" - }, - Permissions: 2205281600, - mongoURI: process.env.mongoURI || "mongodb://localhost:27017", - dbo: process.env.dbo || "knoldus", - Presence: { - type: PresenceTypes.Watching, - name: "DayZ Logs", // What message you want after type - status: PresenceStatus.Online - }, -} diff --git a/src/config/config.ts b/src/config/config.ts new file mode 100644 index 0000000..5e9c897 --- /dev/null +++ b/src/config/config.ts @@ -0,0 +1,62 @@ +import { version } from "../../package.json" +import { ActivityType, PresenceUpdateStatus, OAuth2Scopes } from "discord.js"; +require("dotenv").config(); + +export const enum DevelopmentBranch { + Dev = "DEV.", + Prod = "PROD.", +}; + +export const enum Colors { + Default = "#8a7c72", + DarkRed = "#ba0f0f", + Red = "#f55c5c", + Green = "#32a852", + Yellow = "#ffb01f", +}; + +export interface ConfigPresence { + type: ActivityType; + name: string; + status: PresenceUpdateStatus; +}; + +export interface Config { + Dev: DevelopmentBranch; + Version: string; + Admins: Array; + SupportServer: string; + Token: string; + SecretKey: string; + SecretIv: string; + EncryptionMethod: string; + Scopes: Array; + IconURL: string; + AvatarData: string; + Permissions: number; + MongoURI: string; + DBO: string; + Presence: ConfigPresence; +}; + +export const config: Config = { + Dev: process.env.Dev || DevelopmentBranch.Dev, + Version: version, + Admins: ["362791661274660874", "329371697570381824"], // Admins of the bot + SupportServer: "https://discord.gg/KVFJCvvFtK", // Support Server Link + Token: process.env.token || "", //Discord Bot Token + SecretKey: process.env.key || "01234567891", + SecretIv: process.env.iv || "9876543210", + EncryptionMethod: process.env.encryptionMethod || "aes-256-cbc", + Scopes: [OAuth2Scopes.Identify, OAuth2Scopes.Guilds, OAuth2Scopes.ApplicationsCommands], //Discord OAuth2 Scopes + IconURL: "https://cdn.discordapp.com/app-icons/1049045393415098450/f8e7f76ac9e843360b989c796fc21990.png?size=256", + AvatarData: "data:image/png;base64,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", + Permissions: 2205281600, + MongoURI: process.env.mongoURI || "mongodb://localhost:27017", + DBO: process.env.dbo || "knoldus", + Presence: { + type: ActivityType.Watching, + name: "DayZ Logs", // What message you want after type + status: PresenceUpdateStatus.Online + }, +}; diff --git a/src/database/destinations.js b/src/database/destinations.ts similarity index 94% rename from src/database/destinations.js rename to src/database/destinations.ts index 172a593..fd919bb 100644 --- a/src/database/destinations.js +++ b/src/database/destinations.ts @@ -1,31 +1,40 @@ -const { calculateVector } = require("../util/Vector"); +import { calculateVector } from "@util/Vector"; -module.exports = { - Missions: { - "dayzOffline.chernarusplus": "Chernarus", - "dayzOffline.enoch": "Livonia", - "dayzOffline.sakhal": "Sakhal", - }, +export const Missions = { + "dayzOffline.chernarusplus": "Chernarus", + "dayzOffline.enoch": "Livonia", + "dayzOffline.sakhal": "Sakhal", +} as const; - // Calculates the nearest location to a given coordinate - nearest: (pos, mission) => { - let tempDest; - let lastDist = 1000000; - let destination_dir; - for (let i = 0; i < destinations[mission].length; i++) { - let { distance, theta, dir } = calculateVector(pos, destinations[mission][i].coord); - if (distance < lastDist) { - tempDest = destinations[mission][i].name; - lastDist = distance; - destination_dir = dir; - } +export type MissionKey = keyof typeof Missions; +export type MissionName = typeof Missions[MissionKey]; + +export type Position = [number, number]; + +// Calculates the nearest location to a given coordinate +export function nearest(pos: Position, mission: MissionName): string { + let tempDest; + let lastDist = 1000000; + let destination_dir; + + for (let i = 0; i < destinations[mission].length; i++) { + let { distance, theta, dir } = calculateVector(pos, destinations[mission][i].coord); + if (distance < lastDist) { + tempDest = destinations[mission][i].name; + lastDist = distance; + destination_dir = dir; } - return lastDist > 500 ? `${destination_dir} of ${tempDest}` : `Near ${tempDest}`; } + return lastDist > 500 ? `${destination_dir} of ${tempDest}` : `Near ${tempDest}`; +}; + +interface Destination { + name: string; + coord: Position; } // A curated list of destinations across DayZ Chernarus and Livonia -const destinations = { +const destinations: Record> = { Chernarus: [ { name: "Sinystok", diff --git a/src/database/guild.js b/src/database/guild.js deleted file mode 100644 index 898c6cb..0000000 --- a/src/database/guild.js +++ /dev/null @@ -1,102 +0,0 @@ -module.exports = { - GetGuild: async (client, GuildId) => { - let guild = undefined; - if (client.databaseConnected) guild = await client.dbo.collection("guilds").findOne({ "server.serverID": GuildId }).then(guild => guild); - - // If guild not found, generate guild default - if (!guild) { - guild = {} - guild.server = module.exports.getDefaultSettings(GuildId); - guild.Nitrado = undefined; - if (client.databaseConnected) { - client.dbo.collection("guilds").insertOne(guild, (err, res) => { - if (err) client.error(`GetGuild Insert Error: ${err}`); - }); - } - } - - return { - serverID: GuildId, - Nitrado: guild.Nitrado, - lastLog: guild.server.lastLog, - serverName: guild.server.serverName, - autoRestart: guild.server.autoRestart, - showKillfeedCoords: guild.server.showKillfeedCoords, - showKillfeedWeapon: guild.server.showKillfeedWeapon, - purchaseUAV: guild.server.purchaseUAV, - purchaseEMP: guild.server.purchaseEMP, - allowedChannels: guild.server.allowedChannels, - customChannelStatus: guild.server.allowedChannels.length > 0 ? true : false, - hasBotAdmin: guild.server.botAdminRoles.length > 0 ? true : false, - - killfeedChannel: guild.server.killfeedChannel, - connectionLogsChannel: guild.server.connectionLogsChannel, - activePlayersChannel: guild.server.activePlayersChannel, - welcomeChannel: guild.server.welcomeChannel, - - factionArmbands: guild.server.factionArmbands, - usedArmbands: guild.server.usedArmbands, - excludedRoles: guild.server.excludedRoles, - hasExcludedRoles: guild.server.excludedRoles.length > 0 ? true : false, - botAdminRoles: guild.server.botAdminRoles, - - alarms: guild.server.alarms, - events: guild.server.events, - uavs: guild.server.uavs, - - incomeRoles: guild.server.incomeRoles, - incomeLimiter: guild.server.incomeLimiter, - - startingBalance: guild.server.startingBalance, - uavPrice: guild.server.uavPrice, - empPrice: guild.server.empPrice, - - linkedGamertagRole: guild.server.linkedGamertagRole, - memberRole: guild.server.memberRole, - adminRole: guild.server.adminRole, - - combatLogTimer: guild.server.combatLogTimer, - }; - }, - - getDefaultSettings(GuildId) { - return { - serverID: GuildId, - lastLog: null, - serverName: "our server!", - autoRestart: 0, - showKillfeedCoords: 0, - showKillfeedWeapon: 0, - purchaseUAV: 1, // Allow/Disallow purchase of UAVs - purchaseEMP: 1, // Allow/Disallow purchase of EMPs - allowedChannels: [], - - killfeedChannel: "", - connectionLogsChannel: "", - activePlayersChannel: "", - welcomeChannel: "", - - factionArmbands: {}, - usedArmbands: [], - excludedRoles: [], - botAdminRoles: [], - - alarms: [], - events: [], - uavs: [], - - incomeRoles: [], - incomeLimiter: 168, // # of hours in 7 days - - startingBalance: 500, - uavPrice: 50000, - empPrice: 500000, - - linkedGamertagRole: "", - memberRole: "", - adminRole: "", - - combatLogTimer: 5, // minutes - } - } -} diff --git a/src/database/guild.ts b/src/database/guild.ts new file mode 100644 index 0000000..33d51a6 --- /dev/null +++ b/src/database/guild.ts @@ -0,0 +1,193 @@ +import { Snowflake } from "discord.js"; +import DayZR from "../DayZRBot"; +import { NitradoCredentialStatus } from "@util/NitradoAPI"; + +export const enum IntegerBoolean { + FALSE, + TRUE +}; + +export interface UAV { + // TODO: fill this out +}; + +export interface Alarm { + // TODO: fill this out +}; + +export interface NitradoConfig { + ServerID: string; + UserID: string; + Auth: string; + Status: NitradoCredentialStatus; +}; + +interface GuildConfigAttributes { + serverID: Snowflake; + lastLog: string | null; + serverName: string; + autoRestart: IntegerBoolean; + showKillfeedCoords: IntegerBoolean; + showKillfeedWeapon: IntegerBoolean; + purchaseUAV: IntegerBoolean; + purchaseEMP: IntegerBoolean; + allowedChannels: Array; + customChannelStatus?: boolean; // optional - generated outside of DB + hasBotAdmin?: boolean; // optional - generated outside of DB + + killfeedChannel: Snowflake; + connectionLogsChannel: Snowflake; + activePlayersChannel: Snowflake; + welcomeChannel: Snowflake; + + factionArmbands: any; + usedArmbands: Array; + excludedRoles: Array; + hasExcludedRoles?: boolean; // optional - generated outside of DB + botAdminRoles: Array; + + alarms: Array; + events: Array; + uavs: Array; + + incomeRoles: Array; + incomeLimiter: number; + + startingBalance: number; + uavPrice: number; + empPrice: number; + + linkedGamertagRole: Snowflake; + memberRole: Snowflake; + adminRole: Snowflake; + + combatLogTimer: number; +} + +interface GuildConfigDB { + server: GuildConfigAttributes; + Nitrado: NitradoConfig | null; +}; + +// TODO: have better names, i.e. combatLogTimer in seconds or minutes? inclomeLimiter? +// TODO: figure out interface of + +// Also this is so stupid, in the DB all server attributes are under server, +// while in the code we almost always have the attributes directly in top +// level of object, i.e. guild.startingBalance instead of guild.server.startingBalance +export interface GuildConfig extends GuildConfigAttributes { + Nitrado: NitradoConfig | null; +} + +export async function GetGuild(client: DayZR, GuildId: Snowflake): Promise +{ + let guild: GuildConfigDB | null = null; + if (client.databaseConnected) + { + guild = await client.dbo.collection("guilds").findOne( + { + "server.serverID": GuildId + } + ).then((guild: GuildConfigDB) => guild); + } + + // If guild not found, generate guild default + if (!guild) + { + guild = { + server: getDefaultSettings(GuildId), + Nitrado: null, + }; + + if (client.databaseConnected) + { + client.dbo.collection("guilds").insertOne(guild, (err: string) => { + if (err) client.error(`GetGuild Insert Error: ${err}`); + }); + } + } + + return { + serverID: GuildId, + Nitrado: guild.Nitrado, + lastLog: guild.server.lastLog, + serverName: guild.server.serverName, + autoRestart: guild.server.autoRestart, + showKillfeedCoords: guild.server.showKillfeedCoords, + showKillfeedWeapon: guild.server.showKillfeedWeapon, + purchaseUAV: guild.server.purchaseUAV, + purchaseEMP: guild.server.purchaseEMP, + allowedChannels: guild.server.allowedChannels, + customChannelStatus: guild.server.allowedChannels.length > 0, + hasBotAdmin: guild.server.botAdminRoles.length > 0, + + killfeedChannel: guild.server.killfeedChannel, + connectionLogsChannel: guild.server.connectionLogsChannel, + activePlayersChannel: guild.server.activePlayersChannel, + welcomeChannel: guild.server.welcomeChannel, + + factionArmbands: guild.server.factionArmbands, + usedArmbands: guild.server.usedArmbands, + excludedRoles: guild.server.excludedRoles, + hasExcludedRoles: guild.server.excludedRoles.length > 0, + botAdminRoles: guild.server.botAdminRoles, + + alarms: guild.server.alarms, + events: guild.server.events, + uavs: guild.server.uavs, + + incomeRoles: guild.server.incomeRoles, + incomeLimiter: guild.server.incomeLimiter, + + startingBalance: guild.server.startingBalance, + uavPrice: guild.server.uavPrice, + empPrice: guild.server.empPrice, + + linkedGamertagRole: guild.server.linkedGamertagRole, + memberRole: guild.server.memberRole, + adminRole: guild.server.adminRole, + + combatLogTimer: guild.server.combatLogTimer, + }; +} + +export function getDefaultSettings(GuildId: Snowflake): GuildConfigAttributes { + return { + serverID: GuildId, + lastLog: null, + serverName: "our server!", + autoRestart: IntegerBoolean.FALSE, + showKillfeedCoords: IntegerBoolean.FALSE, + showKillfeedWeapon: IntegerBoolean.FALSE, + purchaseUAV: IntegerBoolean.TRUE, // Allow/Disallow purchase of UAVs + purchaseEMP: IntegerBoolean.TRUE, // Allow/Disallow purchase of EMPs + allowedChannels: [], + + killfeedChannel: "", + connectionLogsChannel: "", + activePlayersChannel: "", + welcomeChannel: "", + + factionArmbands: {}, + usedArmbands: [], + excludedRoles: [], + botAdminRoles: [], + + alarms: [], + events: [], + uavs: [], + + incomeRoles: [], + incomeLimiter: 168, // # of hours in 7 days + + startingBalance: 500, + uavPrice: 50000, + empPrice: 500000, + + linkedGamertagRole: "", + memberRole: "", + adminRole: "", + + combatLogTimer: 5, // minutes + }; +}; diff --git a/src/util/CommandOptionTypes.js b/src/util/CommandOptionTypes.js deleted file mode 100644 index afa4a82..0000000 --- a/src/util/CommandOptionTypes.js +++ /dev/null @@ -1,15 +0,0 @@ -module.exports = { - CommandOptionTypes: { - SubCommand: 1, - SubCommandGroup: 2, - String: 3, - Integer: 4, - Boolean: 5, - User: 6, - Channel: 7, - Role: 8, - Mentionable: 9, - Float: 10, // AKA Number in Discord"s Documentation - Attachment: 11, - } -}; \ No newline at end of file diff --git a/src/util/NitradoAPI.js b/src/util/NitradoAPI.js deleted file mode 100644 index efde904..0000000 --- a/src/util/NitradoAPI.js +++ /dev/null @@ -1,311 +0,0 @@ -const { finished } = require("stream/promises"); -const concat = require("concat-stream"); -const { Readable } = require("stream"); -const FormData = require("form-data"); -const fs = require("fs"); -const maxRetries = 5; -const retryDelay = 5000; // 5 seconds - -// Private functions (only called locally) - -const UploadNitradoFile = async (nitrado_cred, client, remoteDir, remoteFilename, localFileDir) => { - for (let retries = 0; retries <= maxRetries; retries++) { - try { - const res = await fetch(`https://api.nitrado.net/services/${nitrado_cred.ServerID}/gameservers/file_server/upload?` + new URLSearchParams({ - path: remoteDir, - file: remoteFilename - }), { - method: "POST", - headers: { - "Authorization": nitrado_cred.Auth - }, - }).then(response => response.json()); - - let contents = fs.readFileSync(localFileDir, "utf8"); - - const uploadRes = await fetch(res.data.token.url, { - method: "POST", - headers: { - "Content-Type": "application/binary", - token: res.data.token.token - }, - body: contents, - }) - if (!uploadRes.ok) { - client.error(`Failed to upload file to Nitrado (${nitrado_cred.ServerID}): status: ${uploadRes.status}, message: ${res.statusText}: UploadNitradoFile`); - if (retries === 2) return 1; // Return error status on the second failed status code. - } else { - return uploadRes; - } - } catch (error) { - client.error(`UploadNitradoFile: Error connecting to server (${nitrado_cred.ServerID}): ${error.message}`); - if (retries === maxRetries) { - client.error(`UploadNitradoFile: Error connecting to server (${nitrado_cred.ServerID}) after ${maxRetries} retries`); - return 1; - } - } - await new Promise(resolve => setTimeout(resolve, retryDelay)); // Delay before retrying - } -} - -const HandlePlayerBan = async (nitrado_cred, client, gamertag, ban) => { - const data = await module.exports.FetchServerSettings(nitrado_cred, client, "HandlePlayerBan"); // Fetch server status - - if (data && data != 1) { - let bans = data.data.gameserver.settings.general.bans; - if (ban) bans += `\r\n${gamertag}`; - else if (!ban) bans = bans.replace(gamertag, ""); - else client.error("Incorrect Ban Option: HandlePlayerBan"); - - let category = "general"; - let key = "bans"; - return await module.exports.PostServerSettings(nitrado_cred, client, category, key, bans); // returns 1 (failed) or 0 (not failed) - } -} - -const GetRemoteDir = async (nitrado_cred, 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/${nitrado_cred.ServerID}/gameservers/file_server/list${dirParam}`, { - headers: { - "Authorization": nitrado_cred.Auth - } - }).then(response => - response.json().then(data => data) - ).then(res => res); - - if (res.status === "error") return 1; - - return res.data.entries; - } catch (error) { - client.error(`GetRemoteDir: Error connecting to server (${nitrado_cred.ServerID}): ${error}`); - if (retries == maxRetries) { - client.error(`GetRemoteDir: Error connecting to server (${nitrado_cred.ServerID}) after ${maxRetries} retries`); - return 1; - } - } - await new Promise(resolve => setTimeout(resolve, retryDelay)); // Delay before retrying - } -} - -// Public functions (called externally) - -module.exports = { - - DownloadNitradoFile: async (nitrado_cred, client, filename, outputDir) => { - for (let retries = 0; retries <= maxRetries; retries++) { - try { - const res = await fetch(`https://api.nitrado.net/services/${nitrado_cred.ServerID}/gameservers/file_server/download?file=${filename}`, { - headers: { - "Authorization": nitrado_cred.Auth - } - }).then(response => - response.json().then(data => data) - ).then(res => res); - - const stream = fs.createWriteStream(outputDir); - if (!res.data || !res.data.token) { - client.error(`Error downloading File "${filename}": message: ${res.message}: DownloadNitradoFile`); - return 1; - } - const { body } = await fetch(res.data.token.url); - await finished(Readable.fromWeb(body).pipe(stream)); - return 0; - } catch (error) { - client.error(`DownloadNitradoFile: Error connecting to server (${nitrado_cred.ServerID}): ${error.message}`); - if (retries === maxRetries) { - client.error(`DownloadNitradoFile: Error connecting to server (${nitrado_cred.ServerID}) after ${maxRetries} retries`); - return 1; - } - } - await new Promise(resolve => setTimeout(resolve, retryDelay)); // Delay before retrying - } - }, - - /* - Export explicit function names; i.e BanPlayer() & UnbanPlayer() - that call to the private parent function HandlePlayerBan() - rather than write two whole different functions for each. - */ - - BanPlayer: async (nitrado_cred, client, gamertag) => await HandlePlayerBan(nitrado_cred, client, gamertag, true), - UnbanPlayer: async (nitrado_cred, client, gamertag) => await HandlePlayerBan(nitrado_cred, client, gamertag, false), - - RestartServer: async (nitrado_cred, client, restart_message, message) => { - const params = { - restart_message: restart_message, - message: message - }; - for (let retries = 0; retries < maxRetries; retries++) { - try { - const res = await fetch(`https://api.nitrado.net/services/${nitrado_cred.ServerID}/gameservers/restart`, { - method: "POST", - headers: { - "Authorization": nitrado_cred.Auth, - }, - body: JSON.stringify(params) - }); - - if (!res.ok) { - client.error(`Failed to restart Nitrado server (${nitrado_cred.ServerID}): status: ${res.status}, message: ${res.statusText}: RestartServer`); - return 1; // Return error status on failed status code. - } else { - return 0; - } - } catch (error) { - client.error(`RestartServer: Error connecting to server (${nitrado_cred.ServerID}): ${error.message}`); - if (retries === maxRetries) { - client.error(`RestartServer: Error connecting to server (${nitrado_cred.ServerID}) after ${maxRetries} retries`); - return 1; - } - } - await new Promise(resolve => setTimeout(resolve, retryDelay)); // Delay before retrying - } - }, - - FetchServerSettings: async (nitrado_cred, client, fetcher) => { - for (let retries = 0; retries <= maxRetries; retries++) { - try { - // get current status - const res = await fetch(`https://api.nitrado.net/services/${nitrado_cred.ServerID}/gameservers`, { - headers: { - "Authorization": nitrado_cred.Auth - } - }); - - if (!res.ok) { - client.error(`Failed to get Nitrado server stats (${nitrado_cred.ServerID}): status: ${res.status}, message: ${res.statusText}: ${fetcher} via FetchServerSettings`); - if (res.status == 401) return 1; // return immediately if unauthorized - if (retries === 2) return 1; // Return error status on the second failed status code. - } else { - const data = await res.json(); - return data; - } - } catch (error) { - client.error(`${fetcher} via FetchServerSettings: Error connecting to server (${nitrado_cred.ServerID}): ${error.message}`); - if (retries === maxRetries) { - client.error(`${fetcher} via FetchServerSettings: Error connecting to server (${nitrado_cred.ServerID}) after ${maxRetries} retries`); - return 1; - } - } - await new Promise(resolve => setTimeout(resolve, retryDelay)); // Delay before retrying - } - }, - - PostServerSettings: async (nitrado_cred, client, category, key, value) => { - for (let retries = 0; retries <= maxRetries; retries++) { - try { - const formData = new FormData(); - formData.append("category", category); - formData.append("key", key); - formData.append("value", value); - formData.pipe(concat(data => { - async function postData() { - const res = await fetch(`https://api.nitrado.net/services/${nitrado_cred.ServerID}/gameservers/settings`, { - method: "POST", - credentials: "include", - headers: { - ...formData.getHeaders(), - "Authorization": nitrado_cred.Auth - }, - body: data, - }); - if (!res.ok) { - client.error(`Failed to get post Nitrado server settings (${nitrado_cred.ServerID}): status: ${res.status}, message: ${res.statusText}: PostServerSettings`); - if (retries === 2) return 1; // Return error status on the second failed status code. - } else { - const data = await res.json(); - return data; - } - } - postData(); - })); - return 0; - } catch (error) { - client.error(`PostServerSettings: Error connecting to server (${nitrado_cred.ServerID}): ${error.message}`); - if (retries === maxRetries) { - client.error(`PostServerSettings: Error connecting to server (${nitrado_cred.ServerID}) after ${maxRetries} retries`); - return 1; - } - } - await new Promise(resolve => setTimeout(resolve, retryDelay)); // Delay before retrying - } - }, - - CheckServerStatus: async (nitrado_cred, client) => { - const data = await module.exports.FetchServerSettings(nitrado_cred, client, "CheckServerStatus"); // Fetch server status - - if (data && data != 1) { - if (data && data.data.gameserver.status === "stopped") { - client.log(`Restart of Nitrado server ${nitrado_cred.ServerID} has been invoked by the bot, the periodic check showed status of "${data.data.gameserver.status}".`); - // 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 periodic bot check."; - message = "The server was restarted by periodic bot check!"; - - module.exports.RestartServer(nitrado_cred, client, restart_message, message); - } - } - }, - - DisableBaseDamage: async (nitrado_cred, client, preference) => { - const pref = preference ? "1" : "0"; - const posted = await module.exports.PostServerSettings(nitrado_cred, client, "config", "disableBaseDamage", pref); - if (posted == 1) return 1; - - const remoteDirs = await GetRemoteDir(nitrado_cred, client); - if (remoteDirs == 1) return 1; - const basePath = remoteDirs.filter(dir => dir.type == "dir")[0].path - const remoteDirsFromBase = await GetRemoteDir(nitrado_cred, client, basePath); - if (remoteDirsFromBase == 1) return 1; - const missionPath = remoteDirsFromBase[0].path; - const cfggameplayPath = `${missionPath}/cfggameplay.json`; - - const jsonDir = `./logs/cfggameplay.json`; - await module.exports.DownloadNitradoFile(nitrado_cred, client, cfggameplayPath, jsonDir); - - let gameplay = JSON.parse(fs.readFileSync(jsonDir)); - gameplay.GeneralData.disableBaseDamage = preference; - - // write JSON to file - fs.writeFileSync(jsonDir, JSON.stringify(gameplay, null, 2)); - - const uploaded = await UploadNitradoFile(nitrado_cred, client, missionPath, "cfggameplay.json", jsonDir); - if (uploaded == 1) return 1; - - return 0; - }, - - DisableContainerDamage: async (nitrado_cred, client, preference) => { - const pref = preference ? "1" : "0"; - const posted = await module.exports.PostServerSettings(nitrado_cred, client, "config", "disableContainerDamage", pref); - if (posted == 1) return 1; - - const remoteDirs = await GetRemoteDir(nitrado_cred, client); - if (remoteDirs == 1) return 1; - const basePath = remoteDirs.filter(dir => dir.type == "dir")[0].path - const remoteDirsFromBase = await GetRemoteDir(nitrado_cred, client, basePath); - if (remoteDirsFromBase == 1) return 1; - const missionPath = remoteDirsFromBase[0].path; - const cfggameplayPath = `${missionPath}/cfggameplay.json`; - - const jsonDir = `./logs/cfggameplay.json`; - await module.exports.DownloadNitradoFile(nitrado_cred, client, cfggameplayPath, jsonDir); - - let gameplay = JSON.parse(fs.readFileSync(jsonDir)); - gameplay.GeneralData.disableContainerDamage = preference; - - // write JSON to file - fs.writeFileSync(jsonDir, JSON.stringify(gameplay, null, 2)); - - const uploaded = await UploadNitradoFile(nitrado_cred, client, missionPath, "cfggameplay.json", jsonDir); - if (uploaded == 1) return 1; - - return 0; - }, - - NitradoCredentialStatus: { - FAILED: "FAILED", - OK: "OK", - }, -} diff --git a/src/util/NitradoAPI.ts b/src/util/NitradoAPI.ts new file mode 100644 index 0000000..073906d --- /dev/null +++ b/src/util/NitradoAPI.ts @@ -0,0 +1,311 @@ +import { finished } from "stream/promises"; +const concat = require("concat-stream"); // convert to import ? +import { Readable } from "stream"; +import FormData from "form-data"; +import * as fs from "fs"; + +const MAX_RETRIES = 5; +const RETRY_DELAY_MS = 5000; // 5 seconds + +export const enum NitradoCredentialStatus { + FAILED = "FAILED", + OK = "OK", +}; + +/** + * TODO: I have littered this file with "any" types just to temporarily have no errors after converting from .js to .ts + * come back and actually go through line by line and clean this whole file + */ + +const UploadNitradoFile = async (nitrado_cred: any, client: any, remoteDir: any, remoteFilename: any, localFileDir: any) => { + for (let retries = 0; retries <= MAX_RETRIES; retries++) { + try { + const res = await fetch(`https://api.nitrado.net/services/${nitrado_cred.ServerID}/gameservers/file_server/upload?` + new URLSearchParams({ + path: remoteDir, + file: remoteFilename + }), { + method: "POST", + headers: { + "Authorization": nitrado_cred.Auth + }, + }).then(response => response.json()); + + let contents = fs.readFileSync(localFileDir, "utf8"); + + const uploadRes = await fetch(res.data.token.url, { + method: "POST", + headers: { + "Content-Type": "application/binary", + token: res.data.token.token + }, + body: contents, + }) + if (!uploadRes.ok) { + client.error(`Failed to upload file to Nitrado (${nitrado_cred.ServerID}): status: ${uploadRes.status}, message: ${res.statusText}: UploadNitradoFile`); + if (retries === 2) return 1; // Return error status on the second failed status code. + } else { + return uploadRes; + } + } catch (error: any) { + client.error(`UploadNitradoFile: Error connecting to server (${nitrado_cred.ServerID}): ${error.message}`); + if (retries === MAX_RETRIES) { + client.error(`UploadNitradoFile: Error connecting to server (${nitrado_cred.ServerID}) after ${MAX_RETRIES} retries`); + return 1; + } + } + await new Promise(resolve => setTimeout(resolve, RETRY_DELAY_MS)); // Delay before retrying + } +} + +const HandlePlayerBan = async (nitrado_cred: any, client: any, gamertag: any, ban: any) => { + const data = await module.exports.FetchServerSettings(nitrado_cred, client, "HandlePlayerBan"); // Fetch server status + + if (data && data != 1) { + let bans = data.data.gameserver.settings.general.bans; + if (ban) bans += `\r\n${gamertag}`; + else if (!ban) bans = bans.replace(gamertag, ""); + else client.error("Incorrect Ban Option: HandlePlayerBan"); + + let category = "general"; + let key = "bans"; + return await module.exports.PostServerSettings(nitrado_cred, client, category, key, bans); // returns 1 (failed) or 0 (not failed) + } +} + +const GetRemoteDir = async (nitrado_cred: any, client: any, dir = "") => { + const dirParam = client.exists(dir) ? `?dir=${dir}` : ""; + for (let retries = 0; retries <= MAX_RETRIES; retries++) { + try { + const res = await fetch(`https://api.nitrado.net/services/${nitrado_cred.ServerID}/gameservers/file_server/list${dirParam}`, { + headers: { + "Authorization": nitrado_cred.Auth + } + }).then(response => + response.json().then(data => data) + ).then(res => res); + + if (res.status === "error") return 1; + + return res.data.entries; + } catch (error) { + client.error(`GetRemoteDir: Error connecting to server (${nitrado_cred.ServerID}): ${error}`); + if (retries == MAX_RETRIES) { + client.error(`GetRemoteDir: Error connecting to server (${nitrado_cred.ServerID}) after ${MAX_RETRIES} retries`); + return 1; + } + } + await new Promise(resolve => setTimeout(resolve, RETRY_DELAY_MS)); // Delay before retrying + } +} + +/*** exported function ***/ +export const DownloadNitradoFile = async (nitrado_cred: any, client: any, filename: any, outputDir: any) => { + for (let retries = 0; retries <= MAX_RETRIES; retries++) { + try { + const res = await fetch(`https://api.nitrado.net/services/${nitrado_cred.ServerID}/gameservers/file_server/download?file=${filename}`, { + headers: { + "Authorization": nitrado_cred.Auth + } + }).then(response => + response.json().then(data => data) + ).then(res => res); + + const stream: any = fs.createWriteStream(outputDir); + if (!res.data || !res.data.token) { + client.error(`Error downloading File "${filename}": message: ${res.message}: DownloadNitradoFile`); + return 1; + } + const { body }: any = await fetch(res.data.token.url); + await finished(Readable.fromWeb(body).pipe(stream)); + return 0; + } catch (error: any) { + client.error(`DownloadNitradoFile: Error connecting to server (${nitrado_cred.ServerID}): ${error.message}`); + if (retries === MAX_RETRIES) { + client.error(`DownloadNitradoFile: Error connecting to server (${nitrado_cred.ServerID}) after ${MAX_RETRIES} retries`); + return 1; + } + } + await new Promise(resolve => setTimeout(resolve, RETRY_DELAY_MS)); // Delay before retrying + } +}; + +/* + Export explicit function names; i.e BanPlayer() & UnbanPlayer() + that call to the private parent function HandlePlayerBan() + rather than write two whole different functions for each. +*/ + +export const BanPlayer = async (nitrado_cred: any, client: any, gamertag: any) => await HandlePlayerBan(nitrado_cred, client, gamertag, true); +export const UnbanPlayer = async (nitrado_cred: any, client: any, gamertag: any) => await HandlePlayerBan(nitrado_cred, client, gamertag, false); + +export const RestartServer = async (nitrado_cred: any, client: any, restart_message: any, message: any) => { + const params = { + restart_message: restart_message, + message: message + }; + for (let retries = 0; retries < MAX_RETRIES; retries++) { + try { + const res = await fetch(`https://api.nitrado.net/services/${nitrado_cred.ServerID}/gameservers/restart`, { + method: "POST", + headers: { + "Authorization": nitrado_cred.Auth, + }, + body: JSON.stringify(params) + }); + + if (!res.ok) { + client.error(`Failed to restart Nitrado server (${nitrado_cred.ServerID}): status: ${res.status}, message: ${res.statusText}: RestartServer`); + return 1; // Return error status on failed status code. + } else { + return 0; + } + } catch (error: any) { + client.error(`RestartServer: Error connecting to server (${nitrado_cred.ServerID}): ${error.message}`); + if (retries === MAX_RETRIES) { + client.error(`RestartServer: Error connecting to server (${nitrado_cred.ServerID}) after ${MAX_RETRIES} retries`); + return 1; + } + } + await new Promise(resolve => setTimeout(resolve, RETRY_DELAY_MS)); // Delay before retrying + } +}; + +export const FetchServerSettings = async (nitrado_cred: any, client: any, fetcher: any) => { + for (let retries = 0; retries <= MAX_RETRIES; retries++) { + try { + // get current status + const res = await fetch(`https://api.nitrado.net/services/${nitrado_cred.ServerID}/gameservers`, { + headers: { + "Authorization": nitrado_cred.Auth + } + }); + + if (!res.ok) { + client.error(`Failed to get Nitrado server stats (${nitrado_cred.ServerID}): status: ${res.status}, message: ${res.statusText}: ${fetcher} via FetchServerSettings`); + if (res.status == 401) return 1; // return immediately if unauthorized + if (retries === 2) return 1; // Return error status on the second failed status code. + } else { + const data = await res.json(); + return data; + } + } catch (error: any) { + client.error(`${fetcher} via FetchServerSettings: Error connecting to server (${nitrado_cred.ServerID}): ${error.message}`); + if (retries === MAX_RETRIES) { + client.error(`${fetcher} via FetchServerSettings: Error connecting to server (${nitrado_cred.ServerID}) after ${MAX_RETRIES} retries`); + return 1; + } + } + await new Promise(resolve => setTimeout(resolve, RETRY_DELAY_MS)); // Delay before retrying + } +}; + +export const PostServerSettings = async (nitrado_cred: any, client: any, category: any, key: any, value: any) => { + for (let retries = 0; retries <= MAX_RETRIES; retries++) { + try { + const formData = new FormData(); + formData.append("category", category); + formData.append("key", key); + formData.append("value", value); + formData.pipe(concat((data: any) => { + async function postData() { + const res = await fetch(`https://api.nitrado.net/services/${nitrado_cred.ServerID}/gameservers/settings`, { + method: "POST", + credentials: "include", + headers: { + ...formData.getHeaders(), + "Authorization": nitrado_cred.Auth + }, + body: data, + }); + if (!res.ok) { + client.error(`Failed to get post Nitrado server settings (${nitrado_cred.ServerID}): status: ${res.status}, message: ${res.statusText}: PostServerSettings`); + if (retries === 2) return 1; // Return error status on the second failed status code. + } else { + const data = await res.json(); + return data; + } + } + postData(); + })); + return 0; + } catch (error: any) { + client.error(`PostServerSettings: Error connecting to server (${nitrado_cred.ServerID}): ${error.message}`); + if (retries === MAX_RETRIES) { + client.error(`PostServerSettings: Error connecting to server (${nitrado_cred.ServerID}) after ${MAX_RETRIES} retries`); + return 1; + } + } + await new Promise(resolve => setTimeout(resolve, RETRY_DELAY_MS)); // Delay before retrying + } +}; + +export const CheckServerStatus = async (nitrado_cred: any, client: any) => { + const data = await module.exports.FetchServerSettings(nitrado_cred, client, "CheckServerStatus"); // Fetch server status + + if (data && data != 1) { + if (data && data.data.gameserver.status === "stopped") { + client.log(`Restart of Nitrado server ${nitrado_cred.ServerID} has been invoked by the bot, the periodic check showed status of "${data.data.gameserver.status}".`); + // Write optional "restart_message" to set in the Nitrado server logs and send a notice "message" to your server community. + let restart_message = "Server being restarted by periodic bot check."; + let message = "The server was restarted by periodic bot check!"; + + module.exports.RestartServer(nitrado_cred, client, restart_message, message); + } + } +}; + +export const DisableBaseDamage = async (nitrado_cred: any, client: any, preference: any) => { + const pref = preference ? "1" : "0"; + const posted = await module.exports.PostServerSettings(nitrado_cred, client, "config", "disableBaseDamage", pref); + if (posted == 1) return 1; + + const remoteDirs = await GetRemoteDir(nitrado_cred, client); + if (remoteDirs == 1) return 1; + const basePath = remoteDirs.filter((dir: any) => dir.type == "dir")[0].path + const remoteDirsFromBase = await GetRemoteDir(nitrado_cred, client, basePath); + if (remoteDirsFromBase == 1) return 1; + const missionPath = remoteDirsFromBase[0].path; + const cfggameplayPath = `${missionPath}/cfggameplay.json`; + + const jsonDir = `./logs/cfggameplay.json`; + await module.exports.DownloadNitradoFile(nitrado_cred, client, cfggameplayPath, jsonDir); + + let gameplay = JSON.parse(fs.readFileSync(jsonDir, "utf-8")); + gameplay.GeneralData.disableBaseDamage = preference; + + // write JSON to file + fs.writeFileSync(jsonDir, JSON.stringify(gameplay, null, 2)); + + const uploaded = await UploadNitradoFile(nitrado_cred, client, missionPath, "cfggameplay.json", jsonDir); + if (uploaded == 1) return 1; + + return 0; +}; + +export const DisableContainerDamage = async (nitrado_cred: any, client: any, preference: any) => { + const pref = preference ? "1" : "0"; + const posted = await module.exports.PostServerSettings(nitrado_cred, client, "config", "disableContainerDamage", pref); + if (posted == 1) return 1; + + const remoteDirs = await GetRemoteDir(nitrado_cred, client); + if (remoteDirs == 1) return 1; + const basePath = remoteDirs.filter((dir: any) => dir.type == "dir")[0].path + const remoteDirsFromBase = await GetRemoteDir(nitrado_cred, client, basePath); + if (remoteDirsFromBase == 1) return 1; + const missionPath = remoteDirsFromBase[0].path; + const cfggameplayPath = `${missionPath}/cfggameplay.json`; + + const jsonDir = `./logs/cfggameplay.json`; + await module.exports.DownloadNitradoFile(nitrado_cred, client, cfggameplayPath, jsonDir); + + let gameplay = JSON.parse(fs.readFileSync(jsonDir, "utf-8")); + gameplay.GeneralData.disableContainerDamage = preference; + + // write JSON to file + fs.writeFileSync(jsonDir, JSON.stringify(gameplay, null, 2)); + + const uploaded = await UploadNitradoFile(nitrado_cred, client, missionPath, "cfggameplay.json", jsonDir); + if (uploaded == 1) return 1; + + return 0; +}; diff --git a/tsconfig.json b/tsconfig.json index 6a66e90..b9f2d3b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,7 +9,12 @@ "skipLibCheck": true, "resolveJsonModule": true, "forceConsistentCasingInFileNames": true, - "allowJs": true + "allowJs": true, + "baseUrl": "./src", + "paths": { + "@util/*": ["util/*"], + "@db/*": ["database/*"] + } }, "include": ["src"], "exclude": ["node_modules"]