diff --git a/.gitignore b/.gitignore index 1be8645..3c2446e 100644 --- a/.gitignore +++ b/.gitignore @@ -4,12 +4,10 @@ node_modules/* # Testing/dev related *_test.js dev-*.js +commands/debug.js # Logs logs/* # env .env - -# Admin Script backups -admin/backup/* diff --git a/commands/debug.js b/commands/debug.js deleted file mode 100644 index 9d7c8a5..0000000 --- a/commands/debug.js +++ /dev/null @@ -1,30 +0,0 @@ -const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require('discord.js'); -const CommandOptions = require('../util/CommandOptionTypes').CommandOptionTypes; - -module.exports = { - name: "debug", - debug: true, - global: false, - description: "debugging...", - usage: "", - permissions: { - channel: ["VIEW_CHANNEL", "SEND_MESSAGES", "EMBED_LINKS"], - member: [], - }, - options: [], - SlashCommand: { - /** - * - * @param {require("../structures/QuarksBot")} client - * @param {import("discord.js").Message} message - * @param {string[]} args - * @param {*} param3 - */ - run: async (client, interaction, args, { GuildDB }) => { - if (!client.config.Admins.includes(interaction.member.user.id)) return interaction.send({ content: 'Only developers can access this command.', flags: (1 << 6) }) - - return interaction.send({ content: `Hello ${interaction.member.user.id}, you are my creator!!` }) - }, - }, - Interactions: {} -} \ No newline at end of file diff --git a/config/config.js b/config/config.js index 9505356..8d936a4 100644 --- a/config/config.js +++ b/config/config.js @@ -27,7 +27,8 @@ module.exports = { SecretIv: process.env.iv || "9876543210", EncryptionMethod: process.env.encryptionMethod || "aes-256-cbc", Scopes: ["identify", "guilds", "applications.commands"], //Discord OAuth2 Scopes - IconURL: "", + 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", diff --git a/package.json b/package.json index 7e5352e..cc94097 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dayzr-bot", - "version": "13.3.12", + "version": "13.3.21", "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 8750a4d..68ece1b 100644 --- a/src/DayzRBot.js +++ b/src/DayzRBot.js @@ -11,6 +11,7 @@ const { HandlePlayerLogs, HandleActivePlayersList } = require('../util/LogsHandl const { HandleKillfeed, UpdateLastDeathDate } = require('../util/KillfeedHandler'); const { HandleExpiredUAVs, HandleEvents, PlaceFireplaceInAlarm } = require('../util/AlarmsHandler'); const { decrypt } = require('../util/Cryptic'); +const { GetWebhook, WebhookSend } = require("../util/WebhookHandler"); // Data structures imports const { getDefaultPlayer, UpdatePlayer } = require('../database/player'); @@ -66,12 +67,15 @@ class DayzRBot extends Client { this.db; this.dbo; + this.databaseConnected = false; - this.arInterval = arInterval; - this.arIntervalIds = new Map(); - this.playerSessions = new Map(); - this.logHistory = new Map(); - this.alarmPingQueue = new Map(); + this.arInterval = arInterval; + this.arIntervalIds = new Map(); + this.playerSessions = new Map(); + this.logHistory = new Map(); + this.alarmPingQueue = new Map(); + this.playerListMsgIds = new Map(); + this.initialize(); this.LoadCommandsAndInteractionHandlers(); this.LoadEvents(); @@ -99,15 +103,15 @@ class DayzRBot extends Client { // Free unused armbands for related commands if (['armbands', 'claim', 'factions'].includes(command)) { for (const [factionID, data] of Object.entries(GuildDB.factionArmbands)) { - const guild = client.guilds.cache.get(GuildDB.serverID); + const guild = this.guilds.cache.get(GuildDB.serverID); const role = guild.roles.cache.find(role => role.id == factionID); if (!role) { let query = { $pull: { 'server.usedArmbands': data.armband }, $unset: { [`server.factionArmbands.${factionID}`]: "" }, }; - await client.dbo.collection("guilds").updateOne({ 'server.serverID': GuildDB.serverID }, query, (err, res) => { - if (err) return client.sendInternalError(interaction, err); + this.dbo.collection("guilds").updateOne({ 'server.serverID': GuildDB.serverID }, query, (err, res) => { + if (err) return this.sendInternalError(interaction, err); }); } } @@ -213,17 +217,25 @@ class DayzRBot extends Client { const maxEmbed = 10; this.alarmPingQueue.forEach(queue => { - queue.forEach((data, channel_id) => { + queue.forEach(async (data, channel_id) => { const channel = this.GetChannel(channel_id); if (!channel) return; - data.forEach((embeds, role) => { + + const NAME = "DayZ.R Zone Alert"; + const webhook = await GetWebhook(this, NAME, channel_id); + + data.forEach(async (embeds, role) => { let embedArrays = []; while (embeds.length > 0); embedArrays.push(embeds.splice(0, maxEmbed)); - for (let i = 0; i < embedArrays.length; i++) { - if (role == '-no-role-ping-') channel.send({ embeds: embedArrays[i] }); - else channel.send({ content: `<@&${role}>`, embeds: embedArrays[i] }); + for (let i = 0; i < embedArrays.length; i++) { + let content = { embeds: embedArrays[i] }; + if (role != '-no-role-ping-') content.content = `<@&${role}>`; + WebhookSend(this, webhook, content); + + // if (role == '-no-role-ping-') channel.send({ embeds: embedArrays[i] }); + // else channel.send({ content: `<@&${role}>`, embeds: embedArrays[i] }); } }); }); @@ -384,8 +396,10 @@ class DayzRBot extends Client { databaselogs.attempts = 0; // reset attempts this.databaseConnected = true; } catch (err) { - databaselogs.attempts++; - let db = (mongoURI.includes("@") ? mongoURI.split("@")[1] : mongoURI.split("//")[1]).endsWith("/") ? mongoURI.slice(0, -1) : mongoURI; + databaselogs.attempts++; + databaselogs.connected = false; + let db = mongoURI.includes("@") ? mongoURI.split("@")[1] : mongoURI.split("//")[1]; + db = db.includes("/") ? db.split("/")[0] : db; this.error(`Failed to connect to mongodb (mongodb://${db}/${dbo}): attempt ${databaselogs.attempts} - ${err}`); failed = true; } @@ -399,7 +413,8 @@ class DayzRBot extends Client { async initialize() { // Wait for MongoDB to connect await this.connectMongo(this.config.mongoURI, this.config.dbo); - + + if (!this.databaseConnected) return; let guilds = await this.dbo.collection("guilds").find({}).toArray(); /* @@ -424,6 +439,8 @@ class DayzRBot extends Client { } this.logHistory.set(guilds[i].Nitrado.ServerID, guilds[i].server.lastLog); // Using Nitrado Server ID over guild ID in case of future support for multiple nitrado servers in a single guild this.playerSessions.set(guilds[i].Nitrado.ServerID, new Map()); // Same reason here as named above. + this.alarmPingQueue.set(guilds[i].serverID, new Map()); // Initialize alarm queue to be empty + this.playerListMsgIds.set(guilds[i].serverID, ""); // Initialize player list message ids this.log(`[${guilds[i].server.serverID}] Initialized existing Nitrado`); } } diff --git a/util/AdminLogsHandler.js b/util/AdminLogsHandler.js index 35f7e6b..b9142d9 100644 --- a/util/AdminLogsHandler.js +++ b/util/AdminLogsHandler.js @@ -1,12 +1,14 @@ const { EmbedBuilder } = require('discord.js'); const { nearest } = require('../database/destinations'); +const { GetWebhook, WebhookSend } = require("../util/WebhookHandler"); module.exports = { SendConnectionLogs: async (client, guild, data) => { if (!client.exists(guild.connectionLogsChannel)) return; const channel = client.GetChannel(guild.connectionLogsChannel); - + if (!channel) return; + let newDt = await client.getDateEST(data.time); let unixTime = Math.floor(newDt.getTime() / 1000); @@ -14,6 +16,9 @@ module.exports = { .setColor(data.connected ? client.config.Colors.Green : client.config.Colors.Red) .setDescription(`**${data.connected ? 'Connect' : 'Disconnect'} Event - \n${data.player} ${data.connected ? 'Connected' : 'Disconnected'}**`); + const NAME = "DayZ.R Admin Logs"; + const webhook = await GetWebhook(client, NAME, guild.connectionLogsChannel); + if (!data.connected) { if (data.lastConnectionDate != null) { let oldUnixTime = Math.floor(data.lastConnectionDate.getTime() / 1000); @@ -22,17 +27,20 @@ module.exports = { } else connectionLog.addFields({ name: '**Session Time**', value: `**Unknown**`, inline: false }); } - if (client.exists(channel)) await channel.send({ embeds: [connectionLog] }); + // if (client.exists(channel)) await channel.send({ embeds: [connectionLog] }); + await WebhookSend(client, webhook, {embeds: [connectionLog]}); }, DetectCombatLog: async (client, guild, data) => { if (!client.exists(data.lastDamageDate)) return; if (!client.exists(guild.connectionLogsChannel)) return; + const channel = client.GetChannel(guild.connectionLogsChannel); + if (!channel) return; // Ensure channel exists const newDt = await client.getDateEST(data.time); const diffSeconds = Math.round((newDt.getTime() - data.lastDamageDate.getTime()) / 1000); - // If diff is greater than 5 minutes, not a combat log + // If diff is greater than configured time in minutes, not a combat log // or if death after last combat if (diffSeconds > (data.combatLogTimer * 60)) return; if (data.lastDamageDate <= data.lastDeathDate) return; @@ -42,9 +50,6 @@ module.exports = { let attacker = await client.dbo.collection("players").findOne({"gamertag": data.lastHitBy}); if (attacker.lastDeathDate > data.lastDamageDate) return; - const channel = client.GetChannel(guild.connectionLogsChannel); - if (!channel) return; - let unixTime = Math.floor(newDt.getTime() / 1000); const destination = nearest(data.pos, guild.Nitrado.Mission); @@ -52,8 +57,12 @@ module.exports = { .setColor(client.config.Colors.Red) .setDescription(`**NOTICE:**\n**${data.player}** has combat logged at when fighting **${data.lastHitBy}\nLocation [${data.pos[0]}, ${data.pos[1]}](https://www.izurvive.com/chernarusplussatmap/#location=${data.pos[0]};${data.pos[1]})**\n${destination}`); - if (client.exists(guild.adminRole)) channel.send({ content: `<@&${guild.adminRole}>` }); - - return channel.send({ embeds: [combatLog] }); + const NAME = "DayZ.R Admin Logs"; + const webhook = await GetWebhook(client, NAME, guild.connectionLogsChannel); + + let content = { embeds: [combatLog] }; + if (client.exists(guild.adminRole)) content.content = `<@&${guild.adminRole}>`; + WebhookSend(client, webhook, content); + // return channel.send({ embeds: [combatLog] }); } }; diff --git a/util/AlarmsHandler.js b/util/AlarmsHandler.js index 5ca8911..d9ed183 100644 --- a/util/AlarmsHandler.js +++ b/util/AlarmsHandler.js @@ -2,6 +2,7 @@ const { BanPlayer, UnbanPlayer } = require('./NitradoAPI'); const { EmbedBuilder } = require('discord.js'); const { nearest } = require('../database/destinations'); const { GetGuild } = require('../database/guild'); +const { GetWebhook, WebhookSend } = require("../util/WebhookHandler"); // Private functions (only called locally) @@ -20,6 +21,10 @@ const ExpireEvent = async(client, guild, e) => { } const HandlePlayerTrackEvent = async (client, guild, e) => { + if (!client.exists(e.channel)) return ExpireEvent(client, guild, e); // Expire event since it has invalid channel. + const channel = client.GetChannel(e.channel); + if (!channel) return; + let player = await client.dbo.collection("players").findOne({"gamertag": e.gamertag}); let newDt = await client.getDateEST(player.time); @@ -31,10 +36,15 @@ const HandlePlayerTrackEvent = async (client, guild, e) => { .setColor(client.config.Colors.Default) .setDescription(`**${e.name} Event**\n${e.gamertag} was located at **[${player.pos[0]}, ${player.pos[1]}](https://www.izurvive.com/chernarusplussatmap/#location=${player.pos[0]};${player.pos[1]})** at \n${destination}`); - if (!client.exists(e.channel)) return ExpireEvent(client, guild, e); // Expire event since it has invalid channel. - const channel = client.GetChannel(e.channel); - if (e.role) channel.send({ content: `<@&${e.role}>`, embeds: [trackEvent] }); - else channel.send({ embeds: [trackEvent] }); + const NAME = "DayZ.R Player Tracker"; + const webhook = await GetWebhook(client, NAME, e.channel); + + let content = { embeds: [trackEvent] }; + if (client.exists(guild.adminRole)) content.content = `<@&${e.role}>`; + WebhookSend(client, webhook, content); + + // if (e.role) channel.send({ content: `<@&${e.role}>`, embeds: [trackEvent] }); + // else channel.send({ embeds: [trackEvent] }); let now = new Date(); let diff = ((now - e.creationDate) / 1000) / 60; @@ -157,6 +167,7 @@ module.exports = { if (distance < alarm.radius) { const channel = client.GetChannel(alarm.channel); + if (!channel) continue; let newDt = await client.getDateEST(data.time); let unixTime = Math.floor(newDt.getTime()/1000); @@ -166,7 +177,13 @@ module.exports = { .setDescription(`**Zone Ping - **\n**${data.killer}** was located within **${distance} meters** of the Zone **${alarm.name}** __and has been banned for killing **${data.victim}**.__`) .addFields({ name: '**Location**', value: `**[${data.killerPOS[0]}, ${data.killerPOS[1]}](https://www.izurvive.com/chernarusplussatmap/#location=${data.killerPOS[0]};${data.killerPOS[1]})**`, inline: false }) - channel.send({ content: `<@&${alarm.role}>`, embeds: [alarmEmbed] }); + const NAME = "DayZ.R Zone Alert"; + const webhook = await GetWebhook(client, NAME, alarm.channel); + + let content = { content: `<@&${alarm.role}>`, embeds: [alarmEmbed] }; + WebhookSend(client, webhook, content); + + // channel.send({ content: `<@&${alarm.role}>`, embeds: [alarmEmbed] }); BanPlayer(client, data.killer); break; @@ -198,6 +215,7 @@ module.exports = { if (distance < alarm.radius) { const channel = client.GetChannel(alarm.channel); + if (!channel) return; let newDt = await client.getDateEST(info.time); let unixTime = Math.floor(newDt.getTime()/1000); @@ -207,7 +225,13 @@ module.exports = { .setDescription(`**Zone Ping - **\n**${info.player}** was located within **${distance} meters** of the Zone **${alarm.name}** __and has been banned for **placing a fireplace**.__`) .addFields({ name: '**Location**', value: `**[${info.playerPOS[0]}, ${info.playerPOS[1]}](https://www.izurvive.com/chernarusplussatmap/#location=${info.playerPOS[0]};${info.playerPOS[1]})**`, inline: false }) - channel.send({ content: `<@&${alarm.role}>`, embeds: [alarmEmbed] }); + const NAME = "DayZ.R Zone Alert"; + const webhook = await GetWebhook(client, NAME, alarm.channel); + + let content = { content: `<@&${alarm.role}>`, embeds: [alarmEmbed] }; + WebhookSend(client, webhook, content); + + // channel.send({ content: `<@&${alarm.role}>`, embeds: [alarmEmbed] }); BanPlayer(client, info.player); break; diff --git a/util/KillfeedHandler.js b/util/KillfeedHandler.js index 0250e1d..7e6c6c4 100644 --- a/util/KillfeedHandler.js +++ b/util/KillfeedHandler.js @@ -5,6 +5,7 @@ const { nearest } = require('../database/destinations'); const { getDefaultPlayer, UpdatePlayer } = require('../database/player'); const { calculateNewCombatRating } = require('./CombatRatingHandler'); const { weapons, weaponClassOf } = require('../database/weapons'); +const { GetWebhook, WebhookSend } = require("../util/WebhookHandler"); const Templates = { Killed: 1, @@ -79,9 +80,10 @@ module.exports = { }, HandleKillfeed: async (NitradoServerID, client, guild, line) => { - + + const NAME = "DayZ.R Killfeed"; const channel = client.GetChannel(guild.killfeedChannel); - + const killedBy = line.includes('hit by Player') && line.includes('(DEAD)') && line.includes('meters') ? Templates.HitByAndDead : line.includes('hit by Player') && !line.includes('meters') ? Templates.Melee : // Missing meters indicates it was a melee attack. line.includes('hit by Player') ? Templates.HitBy : @@ -133,8 +135,13 @@ module.exports = { if (killedBy == Templates.LandMine || killedBy == Templates.Explosion || killedBy == Templates.Vehicle) { let victimStat = await client.dbo.collection("players").findOne({"playerID": info.victimID}); if (!client.exists(victimStat)) victimStat = getDefaultPlayer(info.victim, info.victimID, NitradoServerID); + victimStat.deaths++; + victimStat.deathStreak++; + victimStat.worstDeathStreak = victimStat.deathStreak > victimStat.worstDeathStreak ? victimStat.deathStreak : victimStat.worstDeathStreak; + victimStat.KDR = victimStat.kills / (victimStat.deaths == 0 ? 1 : victimStat.deaths); // prevent division by 0 + victimStat.killStreak = 0; victimStat.lastDeathDate = newDt; - + const cod = killedBy == Templates.LandMine ? `Land Mine Trap` : killedBy == Templates.Vehicle ? Vehicles[info.causeOfDeath] : info.causeOfDeath; const coord = showCoords ? `\n***Location [${info.victimPOS[0]}, ${info.victimPOS[1]}](https://www.izurvive.com/chernarusplussatmap/#location=${info.victimPOS[0]};${info.victimPOS[1]})***\n${destination}` : ''; @@ -144,9 +151,14 @@ module.exports = { .setColor(client.config.Colors.Default) .setDescription(`**Death Event** - \n**${info.victim}** ${killMessage} a **${cod}.**${coord}`); - if (client.exists(channel)) await channel.send({ embeds: [killEvent] }); await UpdatePlayer(client, victimStat); - return + + if (!channel) return; + const webhook = await GetWebhook(this, NAME, guild.killfeedChannel); + WebhookSend(client, webhook, { embeds: [killEvent]}); + + // if (client.exists(channel)) await channel.send({ embeds: [killEvent] }); + return; } KillInAlarm(client, guild.serverID, info); // check if kill happened in a no kill zone @@ -262,9 +274,16 @@ module.exports = { let weaponClass = weaponClassOf(weapon); killEvent.setThumbnail(weapons[weaponClass][weapon]) } + + if (!channel) return; - if (client.exists(channel)) await channel.send({ embeds: [killEvent] }); - if (client.exists(receivedBounty) && client.exists(channel)) await channel.send({ content: `<@${killerStat.discordID}>`, embeds: [receivedBounty] }); + const webhook = await GetWebhook(this, NAME, guild.killfeedChannel); + + WebhookSend(client, webhook, { embeds: [killEvent] }); + if (client.exists(receivedBounty) && client.exists(channel)) WebhookSend(client, webhook, { content: `<@${killerStat.discordID}>`, embeds: [receivedBounty] }); + + // if (client.exists(channel)) await channel.send({ embeds: [killEvent] }); + // if (client.exists(receivedBounty) && client.exists(channel)) await channel.send({ content: `<@${killerStat.discordID}>`, embeds: [receivedBounty] }); return; } diff --git a/util/LogsHandler.js b/util/LogsHandler.js index e2f2559..873570b 100644 --- a/util/LogsHandler.js +++ b/util/LogsHandler.js @@ -5,8 +5,7 @@ const { getDefaultPlayer } = require('../database/player'); const { FetchServerSettings } = require('../util/NitradoAPI'); const { UpdatePlayer, insertPVPstats, createWeaponStats } = require('../database/player') const { Missions } = require('../database/destinations'); - -let lastSendMessage; +const { GetWebhook, WebhookSend, WebhookMessageEdit } = require("../util/WebhookHandler"); module.exports = { @@ -208,6 +207,7 @@ module.exports = { if (!client.exists(guild.activePlayersChannel)) return; const channel = client.GetChannel(guild.activePlayersChannel); + if (!channel) return; const data = await FetchServerSettings(nitrado_cred, client, 'HandleActivePlayersList'); // Fetch server status const e = data && data !== 1; // Check if data exists @@ -250,11 +250,16 @@ module.exports = { .setTimestamp() .setTitle(`Players Online:`) .setDescription(des || (nodes ? "No Players Online :(" : "")); - - if (lastSendMessage) lastSendMessage.delete().catch(error => client.sendError(channel, `HandleActivePlayersList Error: \n${error}`)); // Remove previous message before reprinting - - return channel.send({ embeds: [serverEmbed, activePlayersEmbed] }).then(sentMessage => - lastSendMessage = sentMessage - ); + + const NAME = "DayZ.R Admin Logs"; + const webhook = await GetWebhook(client, NAME, guild.connectionLogsChannel); + + let id = client.playerListMsgIds.get(guild.serverID); + if (id == "") { + id = await WebhookSend(client, webhook, { embeds: [serverEmbed, activePlayersEmbed] }).id; + client.playerListMsgIds.set(guild.serverID, id); + } else { + WebhookMessageEdit(client, webhook, id, { embeds: [serverEmbed, activePlayersEmbed] }); + } } }; diff --git a/util/WebhookHandler.js b/util/WebhookHandler.js new file mode 100644 index 0000000..bc017d5 --- /dev/null +++ b/util/WebhookHandler.js @@ -0,0 +1,56 @@ +const { makeURLSearchParams } = require('@discordjs/rest'); +const { REST } = require('@discordjs/rest'); +const { Routes } = require('discord.js'); + +const createWebhook = async (client, channel_id, name, avatar) => { + const rest = new REST({ version: '10' }).setToken(client.config.Token); + return await rest.post(Routes.channelWebhooks(channel_id), { + body: { + name: name, + avatar: avatar + } + }); +}; + +module.exports = { + GetWebhook: async (client, webhookName, channel_id) => { + // Get all webhooks from configured channel + const rest = new REST({ version: '10' }).setToken(client.config.Token); + const webhooks = await rest.get(Routes.channelWebhooks(channel_id)); + + let webhook = null; + if (webhooks.length == 0) { + // If no webhook exists, create new webhook with given name for this channel + webhook = createWebhook(client, channel_id, webhookName, client.config.AvatarData); + } else { + // Check existing webhooks for one with given name + let exists = false; + for (let i = 0; i < webhooks.length; i++) { + if (webhooks[i].name == webhookName) { + webhook = webhooks[i]; + exists = true; + break; + } + } + + if (!exists) webhook = createWebhook(client, channel_id, webhookName, client.config.AvatarData); + } + + return webhook; + }, + + WebhookSend: async (client, webhook, content) => { + const rest = new REST({ version: '10' }).setToken(client.config.Token); + return await rest.post(Routes.webhook(webhook.id, webhook.token), { + body: content, + query: makeURLSearchParams({ wait: true }) + }); + }, + + WebhookMessageEdit: async (client, webhook, message_id, content) => { + const rest = new REST({ version: '10' }).setToken(client.config.Token); + return rest.patch(Routes.webhookMessage(webhook.id, webhook.token, message_id), { + body: content + }); + } +}