refactor/logs handler to support migrated player stats

This commit is contained in:
SowinskiBraeden committed 2023-10-27 15:42:48 -07:00
1 parent ffc2e40351
commit 9b849dfc39
12 files changed
+257 -221

No files matched your search

+3 -2
View File
@@ -7,8 +7,9 @@ dev-*.js
# Logs # Logs
logs/* logs/*
npm-debug.log
# env # env
.env .env
.DS_Store
# Admin Script backups
admin/backup/*
+60
View File
@@ -0,0 +1,60 @@
require('dotenv').config({ path: '../.env' });
const fs = require('fs');
const MongoClient = require('mongodb').MongoClient;
const guildId = process.env.GuildID;
const URI = process.env.mongoURI;
const dbo = process.env.dbo;
const NitradoServerID = process.env.SERVER_ID;
const client = new MongoClient(URI);
/*
!WARNING!
THIS SCRIPT IS MEANT ONLY FOR BOT ADMINISTRATORS WHO ARE RUNNING THE BOT + DATABASE
This script will migrate all playerstats from the guildSettings document in the "guilds" collection,
to their own collection as their own documents in the new "players" collection.
Only run this once you have bot version ^12.0.0 or higher.
*/
async function migrate() {
const package = await JSON.parse(fs.readFileSync('../package.json'));
const version = package.version.split('.').map(v => parseInt(v));
if (version[0] < 12) throw new Error('Bot version does not meet requirements: v^12.0.0');
try {
// Get the database and collection on which to run the operation
const database = client.db(dbo);
const players = database.collection("players");
const guilds = database.collection("guilds");
let guild = await guilds.findOne({"server.serverID": guildId});
const dir = __dirname + '/backup';
if (!fs.existsSync(dir)){
fs.mkdirSync(dir);
}
guild.server.playerstats.map(stat => stat.nitradoServerID = NitradoServerID);
// write JSON to file
fs.writeFileSync(`${dir}/player_stats_backup.json`, JSON.stringify(guild.server.playerstats, null, 2));
console.log(`A backup of playerstats was successfully created in ./backup/player_stats_backup.json in case of a fatal error.`);
const result = await players.insertMany(guild.server.playerstats, { ordered: true });
console.log(`${result.insertedCount} documents were inserted`);
delete guild.server.playerstats;
} catch (err) {
throw new Error(`An error occured while attempting to migrate player stats: ${err}`)
} finally {
await client.close();
console.log(`Successfully migrated player stats into the 'players' collection.`);
}
}
migrate()
+1 -1
View File
@@ -1,7 +1,7 @@
const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require('discord.js'); const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require('discord.js');
const CommandOptions = require('../util/CommandOptionTypes').CommandOptionTypes; const CommandOptions = require('../util/CommandOptionTypes').CommandOptionTypes;
const bitfieldCalculator = require('discord-bitfield-calculator'); const bitfieldCalculator = require('discord-bitfield-calculator');
const { getDefaultSettings } = require('../database/guildSettings'); const { getDefaultSettings } = require('../database/guild');
module.exports = { module.exports = {
name: "config", name: "config",
+93
View File
@@ -0,0 +1,93 @@
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);
if (client.databaseConnected) {
thiclients.dbo.collection("guilds").insertOne(guild, (err, res) => {
if (err) throw err;
});
}
}
return {
serverID: GuildId,
autoRestart: guild.server.autoRestart,
showKillfeedCoords: guild.server.showKillfeedCoords,
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,
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,
autoRestart: 0, //
showKillfeedCoords: 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
}
}
}
-41
View File
@@ -1,41 +0,0 @@
module.exports = {
getDefaultSettings(GuildId) {
return {
serverID: GuildId,
autoRestart: 0, //
showKillfeedCoords: 0,
purchaseUAV: 1, // Allow/Disallow purchase of UAVs
purchaseEMP: 1, // Allow/Disallow purchase of EMPs
allowedChannels: [],
killfeedChannel: "",
connectionLogsChannel: "",
activePlayersChannel: "",
welcomeChannel: "",
factionArmbands: {},
usedArmbands: [],
excludedRoles: [],
botAdminRoles: [],
playerstats: [], // to be removed
alarms: [],
events: [],
uavs: [],
incomeRoles: [],
incomeLimiter: 168, // # of hours in 7 days
startingBalance: 500,
uavPrice: 50000,
empPrice: 500000,
linkedGamertagRole: "",
memberRole: "",
adminRole: "",
combatLogTimer: 5, // minutes
}
}
}
@@ -1,5 +1,11 @@
module.exports = { module.exports = {
getDefaultPlayerStats(gt, pID) { UpdatePlayer: async (client, player) => {
return await client.dbo.collection("players").updateOne({"playerID": player.playerID}, {$set: player}, (err, _) => {
if (err) client.error(err);
});
},
getDefaultPlayer(gt, pID) {
return { return {
gamertag: gt, gamertag: gt,
playerID: pID, playerID: pID,
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "dayzr-bot", "name": "dayzr-bot",
"version": "11.5.0", "version": "12.0.0",
"description": "A General Purpose Discord Bot for DayZ Nitrado Servers.", "description": "A General Purpose Discord Bot for DayZ Nitrado Servers.",
"main": "index.js", "main": "index.js",
"nodemonConfig": { "nodemonConfig": {
+29 -81
View File
@@ -11,8 +11,8 @@ const { HandleKillfeed, UpdateLastDeathDate } = require('../util/KillfeedHandler
const { HandleExpiredUAVs, HandleEvents, PlaceFireplaceInAlarm } = require('../util/AlarmsHandler'); const { HandleExpiredUAVs, HandleEvents, PlaceFireplaceInAlarm } = require('../util/AlarmsHandler');
// Data structures imports // Data structures imports
const { getDefaultPlayerStats } = require('../database/playerStatistics'); const { getDefaultPlayer, UpdatePlayer } = require('../database/player');
const { getDefaultSettings } = require('../database/guildSettings'); const { GetGuild } = require('../database/guild');
const path = require("path"); const path = require("path");
const fs = require('fs'); const fs = require('fs');
@@ -134,7 +134,7 @@ class DayzRBot extends Client {
return new Date(f.getTime() + 4 * 3600000); // Add EST time offset to return timestamp in UTC return new Date(f.getTime() + 4 * 3600000); // Add EST time offset to return timestamp in UTC
} }
async readLogs(guildId) { async readLogs(guild) {
const fileStream = fs.createReadStream('./logs/server-logs.ADM'); const fileStream = fs.createReadStream('./logs/server-logs.ADM');
let logHistoryDir = path.join(__dirname, '..', 'logs', 'history-logs.ADM.json'); let logHistoryDir = path.join(__dirname, '..', 'logs', 'history-logs.ADM.json');
@@ -156,25 +156,26 @@ class DayzRBot extends Client {
let logIndex = lines.indexOf(history.lastLog); let logIndex = lines.indexOf(history.lastLog);
let guild = await this.GetGuild(guildId);
if (!this.exists(guild.playerstats)) guild.playerstats = [];
let s = guild.playerstats;
if (this.playerSessions.size === 0) { if (this.playerSessions.size === 0) {
s.map(p => p.connected = false); // assume all players not connected on init only. s.map(p => p.connected = false); // assume all players not connected on init only.
} }
for (let i = logIndex + 1; i < lines.length; i++) { for (let i = logIndex + 1; i < lines.length; i++) {
// Handle lines to skip
if (lines[i].includes('| ####')) continue; if (lines[i].includes('| ####')) continue;
if (lines[i].includes("(id=Unknown") || lines[i].includes("Player \"Unknown Entity\"")) continue; if (lines[i].includes("(id=Unknown") || lines[i].includes("Player \"Unknown Entity\"")) continue;
if ((i - 1) >= 0 && lines[i] == lines[i - 1]) continue; // continue if this line is a duplicate of the last line if ((i - 1) >= 0 && lines[i] == lines[i - 1]) continue; // continue if this line is a duplicate of the last line
if (lines[i].includes('connected') || lines[i].includes('pos=<')) s = await HandlePlayerLogs(this, guildId, s, lines[i], guild.combatLogTimer);
if (lines[i].includes('killed by with') || lines[i].includes('killed by LandMineTrap')) s = await HandleKillfeed(this, guildId, s, lines[i]); // Handles explosive deaths // Handle general logs
if (!(i + 1 >= lines.length) && lines[i + 1].includes('killed by') && lines[i].includes('TransportHit')) s = await HandleKillfeed(this, guildId, s, lines[i]) // Handles vehicle deaths if (lines[i].includes('connected') || lines[i].includes('pos=<')) await HandlePlayerLogs(this, guild, lines[i], guild.combatLogTimer);
if (!(i + 1 >= lines.length) && lines[i + 1].includes('killed by Player') && lines[i].includes('hit by Player')) s = await HandleKillfeed(this, guildId, s, lines[i]); // Handles regular deaths if (lines[i].includes('killed by Zmb') || lines[i].includes('>) died.')) await UpdateLastDeathDate(this, lines[i]); // Updates users last death date for non PVP deaths.
if (lines[i].includes('killed by Player') && !lines[i - 1].includes('hit by Player')) s = await HandleKillfeed(this, guildId, s, lines[i]); // Handles deaths missing hit by log if (lines[i].includes(') placed Fireplace')) await PlaceFireplaceInAlarm(client, guild, lines[i]);
if (lines[i].includes('killed by Zmb') || lines[i].includes('>) died.')) s = await UpdateLastDeathDate(this, s, lines[i]); // Updates users last death date for non PVP deaths.
if (lines[i].includes(') placed Fireplace')) await PlaceFireplaceInAlarm(client, guildId, lines[i]); // Handle killfeed logs
if (lines[i].includes('killed by with') || lines[i].includes('killed by LandMineTrap')) await HandleKillfeed(this, guild, lines[i]); // Handles explosive deaths
if (!(i + 1 >= lines.length) && lines[i + 1].includes('killed by') && lines[i].includes('TransportHit')) await HandleKillfeed(this, guild, lines[i]); // Handles vehicle deaths
if (!(i + 1 >= lines.length) && lines[i + 1].includes('killed by Player') && lines[i].includes('hit by Player')) await HandleKillfeed(this, guild, lines[i]); // Handles regular deaths
if (lines[i].includes('killed by Player') && !lines[i - 1].includes('hit by Player')) await HandleKillfeed(this, guild, lines[i]); // Handles deaths missing hit by log
} }
// Handle alarm pings // Handle alarm pings
@@ -211,8 +212,9 @@ class DayzRBot extends Client {
if (!this.exists(info.player) || !this.exists(info.playerID)) continue; // Skip this player if the player does not exist. if (!this.exists(info.player) || !this.exists(info.playerID)) continue; // Skip this player if the player does not exist.
lastDetectedTime = await this.getDateEST(info.time); lastDetectedTime = await this.getDateEST(info.time);
let playerStat = s.find(stat => stat.playerID == info.playerID);
if (playerStat == undefined) playerStat = getDefaultPlayerStats(info.player, info.playerID); let playerStat = await this.dbo.collection("players").findOne({"playerID": info.playerID});
if (!this.exits(playerStat)) playerStat = getDefaultPlayer(info.player, info.playerID);
if (!previouslyConnected.includes(playerStat) && this.exists(playerStat.lastDisconnectionDate) && playerStat.lastDisconnectionDate !== null && playerStat.lastDisconnectionDate.getTime() > lastDetectedTime.getTime()) continue; // Skip this player if the lastDisconnectionDate time is later than the player log entry. if (!previouslyConnected.includes(playerStat) && this.exists(playerStat.lastDisconnectionDate) && playerStat.lastDisconnectionDate !== null && playerStat.lastDisconnectionDate.getTime() > lastDetectedTime.getTime()) continue; // Skip this player if the lastDisconnectionDate time is later than the player log entry.
@@ -237,22 +239,12 @@ class DayzRBot extends Client {
} }
} }
let playerStatIndex = s.indexOf(playerStat); await UpdatePlayer(this, playerStat);
if (playerStatIndex == -1) s.push(playerStat);
else s[playerStatIndex] = playerStat;
} }
break; break;
} }
} }
await this.dbo.collection("guilds").updateOne({ "server.serverID": guildId }, {
$set: {
"server.playerstats": s
}
}, (err, res) => {
if (err) this.sendError(this.GetChannel(guild.adminLogsChannel), err);
});
history.lastLog = lines[lines.length - 1]; history.lastLog = lines[lines.length - 1];
// write JSON string to a file // write JSON string to a file
@@ -260,8 +252,8 @@ class DayzRBot extends Client {
} }
async logsUpdateTimer(c) { async logsUpdateTimer(c) {
if (this.processingLogs) return; // Process is already running, wait till next scheduled time. if (c.processingLogs) return; // Process is already running, wait till next scheduled time.
this.processingLogs = true; c.processingLogs = true;
let t = new Date(); let t = new Date();
// c.log(`...Logs Tick - ${t.getHours()}:${t.getMinutes()}:${t.getSeconds()}...`); // c.log(`...Logs Tick - ${t.getHours()}:${t.getMinutes()}:${t.getSeconds()}...`);
c.activePlayersTick++; c.activePlayersTick++;
@@ -270,17 +262,19 @@ class DayzRBot extends Client {
const filename = settings.game_specific.log_files.sort((a, b) => a.length - b.length)[0]; const filename = settings.game_specific.log_files.sort((a, b) => a.length - b.length)[0];
const path = `${settings.game_specific.path.slice(0, -1)}${filename.split(settings.game)[1]}`; const path = `${settings.game_specific.path.slice(0, -1)}${filename.split(settings.game)[1]}`;
let guild = await c.GetGuild(c, c.config.GuildID);
await DownloadNitradoFile(c, path, './logs/server-logs.ADM').then(async (status) => { await DownloadNitradoFile(c, path, './logs/server-logs.ADM').then(async (status) => {
if (status == 1) return c.error('...Failed to Download logs...'); if (status == 1) return c.error('...Failed to Download logs...');
// c.log('...Downloaded logs...'); // c.log('...Downloaded logs...');
await c.readLogs(c.config.GuildID).then(async () => { await c.readLogs(guild).then(async () => {
// c.log('...Analyzed logs...'); // c.log('...Analyzed logs...');
HandleExpiredUAVs(c, c.config.GuildID); HandleExpiredUAVs(c, guild);
HandleEvents(c, c.config.GuildID) HandleEvents(c, guild)
if (c.activePlayersTick == 12) await HandleActivePlayersList(c, c.config.GuildID); if (c.activePlayersTick == 12) await HandleActivePlayersList(c, guild);
}) })
}); });
this.processingLogs = false; c.processingLogs = false;
} }
async connectMongo(mongoURI, dbo) { async connectMongo(mongoURI, dbo) {
@@ -422,53 +416,7 @@ class DayzRBot extends Client {
this.guilds.cache.forEach((guild) => RegisterGuildCommands(this, guild.id)); this.guilds.cache.forEach((guild) => RegisterGuildCommands(this, guild.id));
} }
async GetGuild(GuildId) { async GetGuild(GuildId) { return await GetGuild(this, GuildId) }
let guild = undefined;
if (this.databaseConnected) guild = await this.dbo.collection("guilds").findOne({"server.serverID":GuildId}).then(guild => guild);
// If guild not found, generate guild default
if (!guild) {
guild = {}
guild.server = getDefaultSettings(GuildId);
if (this.databaseConnected) {
this.dbo.collection("guilds").insertOne(guild, (err, res) => {
if (err) throw err;
});
}
}
return {
serverID: GuildId,
autoRestart: guild.server.autoRestart,
customChannelStatus: guild.server.allowedChannels.length > 0 ? true : false,
allowedChannels: guild.server.allowedChannels,
factionArmbands: guild.server.factionArmbands,
usedArmbands: guild.server.usedArmbands,
excludedRoles: guild.server.excludedRoles,
hasBotAdmin: guild.server.botAdminRoles.length > 0 ? true : false,
botAdminRoles: guild.server.botAdminRoles,
playerstats: guild.server.playerstats,
alarms: guild.server.alarms,
events: guild.server.events,
uavs: guild.server.uavs,
killfeedChannel: guild.server.killfeedChannel,
showKillfeedCoords: guild.server.showKillfeedCoords,
connectionLogsChannel: guild.server.connectionLogsChannel,
welcomeChannel: guild.server.welcomeChannel,
activePlayersChannel: guild.server.activePlayersChannel,
linkedGamertagRole: guild.server.linkedGamertagRole,
incomeRoles: guild.server.incomeRoles,
incomeLimiter: guild.server.incomeLimiter,
startingBalance: guild.server.startingBalance,
uavPrice: guild.server.uavPrice,
empPrice: guild.server.empPrice,
memberRole: guild.server.memberRole,
adminRole: guild.server.adminRole,
combatLogTimer: guild.server.combatLogTimer,
purchaseUAV: guild.server.purchaseUAV,
purchaseEMP: guild.server.purchaseEMP,
};
}
build() { build() {
this.login(this.config.Token); this.login(this.config.Token);
+3 -6
View File
@@ -4,8 +4,7 @@ const { calculateVector } = require('./vector');
module.exports = { module.exports = {
SendConnectionLogs: async (client, guildId, data) => { SendConnectionLogs: async (client, guild, data) => {
let guild = await client.GetGuild(guildId);
if (!client.exists(guild.connectionLogsChannel)) return; if (!client.exists(guild.connectionLogsChannel)) return;
const channel = client.GetChannel(guild.connectionLogsChannel); const channel = client.GetChannel(guild.connectionLogsChannel);
@@ -27,10 +26,8 @@ module.exports = {
if (client.exists(channel)) await channel.send({ embeds: [connectionLog] }); if (client.exists(channel)) await channel.send({ embeds: [connectionLog] });
}, },
DetectCombatLog: async (client, guildId, data) => { DetectCombatLog: async (client, guild, data) => {
if (!client.exists(data.lastDamageDate)) return; if (!client.exists(data.lastDamageDate)) return;
let guild = await client.GetGuild(guildId);
if (!client.exists(guild.connectionLogsChannel)) return; if (!client.exists(guild.connectionLogsChannel)) return;
const newDt = await client.getDateEST(data.time); const newDt = await client.getDateEST(data.time);
@@ -43,7 +40,7 @@ module.exports = {
// If lastHitBy (attacker) died after shooting this player // If lastHitBy (attacker) died after shooting this player
// then it does not count as combat logging, (the combat ended due to death) // then it does not count as combat logging, (the combat ended due to death)
let attacker = guild.playerstats.find(stat => stat.gamertag = data.lastHitBy); let attacker = await client.dbo.collection("players").findOne({"gamertag": data.lastHitBy});
if (attacker.lastDeathDate > data.lastDamageDate) return; if (attacker.lastDeathDate > data.lastDamageDate) return;
const channel = client.GetChannel(guild.connectionLogsChannel); const channel = client.GetChannel(guild.connectionLogsChannel);
+5 -12
View File
@@ -20,7 +20,7 @@ const ExpireEvent = async(client, guild, e) => {
} }
const HandlePlayerTrackEvent = async (client, guild, e) => { const HandlePlayerTrackEvent = async (client, guild, e) => {
let player = guild.playerstats.find(stat => stat.gamertag == e.gamertag ); let player = await client.dbo.collection("players").findOne({"gamertag": e.gamertag});
let newDt = await client.getDateEST(player.time); let newDt = await client.getDateEST(player.time);
let unixTime = Math.floor(newDt.getTime()/1000); let unixTime = Math.floor(newDt.getTime()/1000);
@@ -58,8 +58,7 @@ const HandlePlayerTrackEvent = async (client, guild, e) => {
module.exports = { module.exports = {
HandleAlarmsAndUAVs: async (client, guildId, data) => { HandleAlarmsAndUAVs: async (client, guild, data) => {
let guild = await client.GetGuild(guildId);
for (let i = 0; i < guild.alarms.length; i++) { for (let i = 0; i < guild.alarms.length; i++) {
let alarm = guild.alarms[i]; let alarm = guild.alarms[i];
@@ -137,8 +136,7 @@ module.exports = {
} }
}, },
HandleExpiredUAVs: async (client, guildId) => { HandleExpiredUAVs: async (client, guild) => {
let guild = await client.GetGuild(guildId);
let uavs = guild.uavs; let uavs = guild.uavs;
let update = false; let update = false;
@@ -199,7 +197,7 @@ module.exports = {
return; return;
}, },
PlaceFireplaceInAlarm: async (client, guildId, line) => { PlaceFireplaceInAlarm: async (client, guild, line) => {
let fireplacePlacement = /(.*) \| Player \"(.*)\" \(id=(.*) pos=<(.*)>\) placed Fireplace/g; let fireplacePlacement = /(.*) \| Player \"(.*)\" \(id=(.*) pos=<(.*)>\) placed Fireplace/g;
let data = [...line.matchAll(fireplacePlacement)][0]; let data = [...line.matchAll(fireplacePlacement)][0];
@@ -212,8 +210,6 @@ module.exports = {
victimPOS: data[4].split(', ').map(v => parseFloat(v)), victimPOS: data[4].split(', ').map(v => parseFloat(v)),
}; };
let guild = await client.GetGuild(guildId);
for (let i = 0; i < guild.alarms.length; i++) { for (let i = 0; i < guild.alarms.length; i++) {
let alarm = guild.alarms[i]; let alarm = guild.alarms[i];
if (alarm.disabled || !alarm.rules.includes('ban_on_fireplace_placement')) continue; if (alarm.disabled || !alarm.rules.includes('ban_on_fireplace_placement')) continue;
@@ -242,10 +238,7 @@ module.exports = {
return; return;
}, },
HandleEvents: async (client, guildId) => { HandleEvents: async (client, guild) => {
let guild = await client.GetGuild(guildId);
for (let i = 0; i < guild.events.length; i++) { for (let i = 0; i < guild.events.length; i++) {
let event = guild.events[i]; let event = guild.events[i];
if (event.type == 'player-track') HandlePlayerTrackEvent(client, guild, event); if (event.type == 'player-track') HandlePlayerTrackEvent(client, guild, event);
+21 -32
View File
@@ -3,7 +3,7 @@ const { createUser, addUser } = require('../database/user');
const { KillInAlarm } = require('./AlarmsHandler'); const { KillInAlarm } = require('./AlarmsHandler');
const { destinations } = require('../database/destinations'); const { destinations } = require('../database/destinations');
const { calculateVector } = require('./vector'); const { calculateVector } = require('./vector');
const { getDefaultPlayerStats } = require('../database/playerStatistics'); const { getDefaultPlayer, UpdatePlayer } = require('../database/player');
const Templates = { const Templates = {
Killed: 1, Killed: 1,
@@ -42,7 +42,7 @@ const Vehicles = {
module.exports = { module.exports = {
// Update last death date for non PVP deaths // Update last death date for non PVP deaths
UpdateLastDeathDate: async (client, stats, line) => { UpdateLastDeathDate: async (client, line) => {
let killedByZmb = /(.*) \| Player \"(.*)\" \(DEAD\) \(id=(.*) pos=<(.*)>\) killed by (.*)/g; let killedByZmb = /(.*) \| Player \"(.*)\" \(DEAD\) \(id=(.*) pos=<(.*)>\) killed by (.*)/g;
let diedTemplate = /(.*) \| Player \"(.*)\" \(DEAD\) \(id=(.*) pos=<(.*)>\) died\. Stats> Water: (.*) Energy: (.*) Bleed sources: (.*)/g; let diedTemplate = /(.*) \| Player \"(.*)\" \(DEAD\) \(id=(.*) pos=<(.*)>\) died\. Stats> Water: (.*) Energy: (.*) Bleed sources: (.*)/g;
@@ -58,19 +58,16 @@ module.exports = {
const newDt = await client.getDateEST(info.time); const newDt = await client.getDateEST(info.time);
let victimStat = stats.find(stat => stat.playerID == info.victimID); let victimStat = await client.dbo.collection("players").findOne({"playerID": info.playerID});
let victimStatIndex = stats.indexOf(victimStat); if (!client.exits(victimStat)) playerStat = getDefaultPlayer(info.player, info.playerID);
if (victimStat == undefined) victimStat = getDefaultPlayerStats(info.victim, info.victimID);
victimStat.lastDeathDate = newDt;
if (victimStatIndex == -1) stats.push(victimStat);
else stats[victimStatIndex] = victimStat;
return stats; victimStat.lastDeathDate = newDt;
return await UpdatePlayer(client, victimStat);
}, },
HandleKillfeed: async (client, guildId, stats, line) => { HandleKillfeed: async (client, guild, line) => {
let guild = await client.GetGuild(guildId);
const channel = client.GetChannel(guild.killfeedChannel); const channel = client.GetChannel(guild.killfeedChannel);
let templateKilled = /(.*) \| Player \"(.*)\" \(DEAD\) \(id=(.*) pos=<(.*)>\) killed by Player \"(.*)\" \(id=(.*) pos=<(.*)>\) with (.*) from (.*) meters /g; let templateKilled = /(.*) \| Player \"(.*)\" \(DEAD\) \(id=(.*) pos=<(.*)>\) killed by Player \"(.*)\" \(id=(.*) pos=<(.*)>\) with (.*) from (.*) meters /g;
@@ -96,7 +93,7 @@ module.exports = {
killedBy == Templates.Vehicle ? [...line.matchAll(vehicleTemplate)][0] : killedBy == Templates.Vehicle ? [...line.matchAll(vehicleTemplate)][0] :
[...line.matchAll(explosionTemplate)][0]; [...line.matchAll(explosionTemplate)][0];
if (!data) return stats; if (!data) return;
// Create base data // Create base data
let info = { let info = {
@@ -124,7 +121,7 @@ module.exports = {
} }
else if (killedBy == Templates.Vehicle) info.causeOfDeath = data[6]; else if (killedBy == Templates.Vehicle) info.causeOfDeath = data[6];
else if (killedBy == Templates.Explosion) info.causeOfDeath = data[5]; else if (killedBy == Templates.Explosion) info.causeOfDeath = data[5];
else return stats; // Unknown template; else return; // Unknown template;
const newDt = await client.getDateEST(info.time); const newDt = await client.getDateEST(info.time);
const unixTime = Math.floor(newDt.getTime()/1000); const unixTime = Math.floor(newDt.getTime()/1000);
@@ -145,12 +142,9 @@ module.exports = {
const destination = lastDist > 500 ? `${destination_dir} of ${tempDest}` : `Near ${tempDest}`; const destination = lastDist > 500 ? `${destination_dir} of ${tempDest}` : `Near ${tempDest}`;
if (killedBy == Templates.LandMine || killedBy == Templates.Explosion || killedBy == Templates.Vehicle) { if (killedBy == Templates.LandMine || killedBy == Templates.Explosion || killedBy == Templates.Vehicle) {
let victimStat = stats.find(stat => stat.playerID == info.victimID) let victimStat = await client.dbo.collection("players").findOne({"playerID": info.victimID});
let victimStatIndex = stats.indexOf(victimStat); if (!client.exits(victimStat)) victimStat = getDefaultPlayer(info.victim, info.victimID);
if (victimStat == undefined) victimStat = getDefaultPlayerStats(info.victim, info.victimID);
victimStat.lastDeathDate = newDt; victimStat.lastDeathDate = newDt;
if (victimStatIndex == -1) stats.push(victimStat);
else stats[victimStatIndex] = victimStat;
const cod = killedBy == Templates.LandMine ? `Land Mine Trap` : const cod = killedBy == Templates.LandMine ? `Land Mine Trap` :
killedBy == Templates.Vehicle ? Vehicles[info.causeOfDeath] : info.causeOfDeath; killedBy == Templates.Vehicle ? Vehicles[info.causeOfDeath] : info.causeOfDeath;
@@ -162,19 +156,17 @@ module.exports = {
.setDescription(`**Death Event** - <t:${unixTime}>\n**${info.victim}** ${killMessage} a **${cod}.**${coord}`); .setDescription(`**Death Event** - <t:${unixTime}>\n**${info.victim}** ${killMessage} a **${cod}.**${coord}`);
if (client.exists(channel)) await channel.send({ embeds: [killEvent] }); if (client.exists(channel)) await channel.send({ embeds: [killEvent] });
return stats; return await UpdatePlayer(client, victimStat);
} }
killerStat
KillInAlarm(client, guildId, info); // check if kill happened in a no kill zone KillInAlarm(client, guildId, info); // check if kill happened in a no kill zone
if (!client.exists(info.victim) || !client.exists(info.victimID) || !client.exists(info.killer) || !client.exists(info.killerID)) return stats; if (!client.exists(info.victim) || !client.exists(info.victimID) || !client.exists(info.killer) || !client.exists(info.killerID)) return stats;
let killerStat = stats.find(stat => stat.playerID == info.killerID) let victimStat = await client.dbo.collection("players").findOne({"playerID": info.victimID});
let victimStat = stats.find(stat => stat.playerID == info.victimID) let killerStat = await client.dbo.collection("players").findOne({"playerID": info.killerID});
let killerStatIndex = stats.indexOf(killerStat); if (!client.exits(victimStat)) victimStat = getDefaultPlayer(info.victim, info.victimID);
let victimStatIndex = stats.indexOf(victimStat); if (!client.exits(killerStat)) killerStat = getDefaultPlayer(info.killer, info.killerID);
if (killerStat == undefined) killerStat = getDefaultPlayerStats(info.killer, info.killerID);
if (victimStat == undefined) victimStat = getDefaultPlayerStats(info.victim, info.victimID);
killerStat.kills++; killerStat.kills++;
killerStat.killStreak++; killerStat.killStreak++;
@@ -198,7 +190,6 @@ module.exports = {
let banking = await client.dbo.collection("users").findOne({"user.userID": killerStat.discordID}).then(banking => banking); let banking = await client.dbo.collection("users").findOne({"user.userID": killerStat.discordID}).then(banking => banking);
if (!banking) { if (!banking) {
banking = await createUser(interaction.member.user.id, GuildDB.serverID, GuildDB.startingBalance, client) banking = await createUser(interaction.member.user.id, GuildDB.serverID, GuildDB.startingBalance, client)
if (!client.exists(banking)) return client.sendInternalError(interaction, err); if (!client.exists(banking)) return client.sendInternalError(interaction, err);
@@ -227,10 +218,8 @@ module.exports = {
victimStat.bounties = []; // clear bounties after claimed victimStat.bounties = []; // clear bounties after claimed
} }
if (killerStatIndex == -1) stats.push(killerStat); await UpdatePlayer(client, victimStat);
else stats[killerStatIndex] = killerStat; await UpdatePlayer(client, killerStat);
if (victimStatIndex == -1) stats.push(victimStat);
else stats[victimStatIndex] = victimStat;
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}` : ''; 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}` : '';
@@ -241,6 +230,6 @@ module.exports = {
if (client.exists(channel)) await channel.send({ embeds: [killEvent] }); if (client.exists(channel)) await channel.send({ embeds: [killEvent] });
if (client.exists(receivedBounty) && client.exists(channel)) await channel.send({ content: `<@${killerStat.discordID}>`, embeds: [receivedBounty] }); if (client.exists(receivedBounty) && client.exists(channel)) await channel.send({ content: `<@${killerStat.discordID}>`, embeds: [receivedBounty] });
return stats; return;
} }
} }
+34 -44
View File
@@ -1,14 +1,15 @@
const { EmbedBuilder } = require('discord.js'); const { EmbedBuilder } = require('discord.js');
const { HandleAlarmsAndUAVs } = require('./AlarmsHandler'); const { HandleAlarmsAndUAVs } = require('./AlarmsHandler');
const { SendConnectionLogs, DetectCombatLog } = require('./AdminLogsHandler'); const { SendConnectionLogs, DetectCombatLog } = require('./AdminLogsHandler');
const { getDefaultPlayerStats } = require('../database/playerStatistics'); const { getDefaultPlayer } = require('../database/player');
const { FetchServerSettings } = require('../util/NitradoAPI'); const { FetchServerSettings } = require('../util/NitradoAPI');
const { UpdatePlayer } = require('../database/player')
let lastSendMessage; let lastSendMessage;
module.exports = { module.exports = {
HandlePlayerLogs: async (client, guildId, stats, line, combatLogTimer = 5) => { HandlePlayerLogs: async (client, GuildDB, line, combatLogTimer = 5) => {
const connectTemplate = /(.*) \| Player \"(.*)\" is connected \(id=(.*)\)/g; const connectTemplate = /(.*) \| Player \"(.*)\" is connected \(id=(.*)\)/g;
const disconnectTemplate = /(.*) \| Player \"(.*)\"\(id=(.*)\) has been disconnected/g; const disconnectTemplate = /(.*) \| Player \"(.*)\"\(id=(.*)\) has been disconnected/g;
@@ -18,7 +19,7 @@ module.exports = {
if (line.includes(' connected')) { if (line.includes(' connected')) {
const data = [...line.matchAll(connectTemplate)][0]; const data = [...line.matchAll(connectTemplate)][0];
if (!data) return stats; if (!data) return;
const info = { const info = {
time: data[1], time: data[1],
@@ -26,12 +27,10 @@ module.exports = {
playerID: data[3], playerID: data[3],
}; };
if (!client.exists(info.player) || !client.exists(info.playerID)) return stats; if (!client.exists(info.player) || !client.exists(info.playerID)) return;
let playerStat = stats.find(stat => stat.playerID == info.playerID);
let playerStatIndex = stats.indexOf(playerStat);
if (playerStat === undefined) playerStat = getDefaultPlayerStats(info.player, info.playerID);
let playerStat = await client.dbo.collection("players").findOne({"playerID": info.playerID});
if (!client.exits(playerStat)) playerStat = getDefaultPlayer(info.player, info.playerID);
const newDt = await client.getDateEST(info.time); const newDt = await client.getDateEST(info.time);
playerStat.lastConnectionDate = newDt; playerStat.lastConnectionDate = newDt;
@@ -51,20 +50,19 @@ module.exports = {
client.playerSessions.set(info.playerID, newSession); client.playerSessions.set(info.playerID, newSession);
} }
if (playerStatIndex === -1) stats.push(playerStat); await SendConnectionLogs(client, GuildDB, {
else stats[playerStatIndex] = playerStat;
await SendConnectionLogs(client, guildId, {
time: info.time, time: info.time,
player: info.player, player: info.player,
connected: true, connected: true,
lastConnectionDate: null, lastConnectionDate: null,
}); });
return await UpdatePlayer(client, playerStat);
} }
if (line.includes(' disconnected')) { if (line.includes(' disconnected')) {
const data = [...line.matchAll(disconnectTemplate)][0]; const data = [...line.matchAll(disconnectTemplate)][0];
if (!data) return stats; if (!data) return;
const info = { const info = {
time: data[1], time: data[1],
@@ -72,11 +70,10 @@ module.exports = {
playerID: data[3], playerID: data[3],
}; };
if (!client.exists(info.player) || !client.exists(info.playerID)) return stats; if (!client.exists(info.player) || !client.exists(info.playerID)) return;
let playerStat = stats.find(stat => stat.playerID == info.playerID); let playerStat = await client.dbo.collection("players").findOne({"playerID": info.playerID});
let playerStatIndex = stats.indexOf(playerStat); if (!client.exits(playerStat)) playerStat = getDefaultPlayer(info.player, info.playerID);
if (playerStat === undefined) playerStat = getDefaultPlayerStats(info.player, info.playerID);
const newDt = await client.getDateEST(info.time); const newDt = await client.getDateEST(info.time);
const unixTime = Math.round(newDt.getTime() / 1000); // Seconds const unixTime = Math.round(newDt.getTime() / 1000); // Seconds
@@ -90,10 +87,7 @@ module.exports = {
playerStat.lastDisconnectionDate = newDt; playerStat.lastDisconnectionDate = newDt;
playerStat.connected = false; playerStat.connected = false;
if (playerStatIndex === -1) stats.push(playerStat); await SendConnectionLogs(client, GuildDB, {
else stats[playerStatIndex] = playerStat;
await SendConnectionLogs(client, guildId, {
time: info.time, time: info.time,
player: info.player, player: info.player,
connected: false, connected: false,
@@ -101,7 +95,7 @@ module.exports = {
}); });
if (combatLogTimer != 0) { if (combatLogTimer != 0) {
DetectCombatLog(client, guildId, { await DetectCombatLog(client, GuildDB, {
time: info.time, time: info.time,
player: info.player, player: info.player,
pos: playerStat.pos, pos: playerStat.pos,
@@ -111,11 +105,13 @@ module.exports = {
combatLogTimer: combatLogTimer, combatLogTimer: combatLogTimer,
}); });
} }
return await UpdatePlayer(client, playerStat);
} }
if (line.includes('pos=<') && !line.includes('hit by')) { if (line.includes('pos=<') && !line.includes('hit by')) {
const data = [...line.matchAll(positionTemplate)][0]; const data = [...line.matchAll(positionTemplate)][0];
if (!data) return stats; if (!data) return;
const info = { const info = {
time: data[1], time: data[1],
@@ -124,11 +120,10 @@ module.exports = {
pos: data[4].split(', ').map(v => parseFloat(v)) pos: data[4].split(', ').map(v => parseFloat(v))
}; };
if (!client.exists(info.player) || !client.exists(info.playerID)) return stats; if (!client.exists(info.player) || !client.exists(info.playerID)) return;
let playerStat = stats.find(stat => stat.playerID == info.playerID); let playerStat = await client.dbo.collection("players").findOne({"playerID": info.playerID});
let playerStatIndex = stats.indexOf(playerStat); if (!client.exits(playerStat)) playerStat = getDefaultPlayer(info.player, info.playerID);
if (playerStat === undefined) playerStat = getDefaultPlayerStats(info.player, info.playerID);
if (!client.exists(playerStat.lastConnectionDate)) playerStat.lastConnectionDate = await client.getDateEST(info.time); if (!client.exists(playerStat.lastConnectionDate)) playerStat.lastConnectionDate = await client.getDateEST(info.time);
playerStat.lastPos = playerStat.pos; playerStat.lastPos = playerStat.pos;
@@ -138,22 +133,21 @@ module.exports = {
playerStat.time = `${info.time} EST`; playerStat.time = `${info.time} EST`;
playerStat.date = await client.getDateEST(info.time); playerStat.date = await client.getDateEST(info.time);
if (playerStatIndex === -1) stats.push(playerStat); if (line.includes('hit by') || line.includes('killed by')) return; // prevent additional information from being fed to Alarms & UAVs
else stats[playerStatIndex] = playerStat;
if (line.includes('hit by') || line.includes('killed by')) return stats; // prevent additional information from being fed to Alarms & UAVs await HandleAlarmsAndUAVs(client, GuildDB, {
HandleAlarmsAndUAVs(client, guildId, {
time: info.time, time: info.time,
player: info.player, player: info.player,
playerID: info.playerID, playerID: info.playerID,
pos: info.pos, pos: info.pos,
}); });
return await UpdatePlayer(client, playerStat)
} }
if (line.includes('hit by Player')) { if (line.includes('hit by Player')) {
const data = line.includes('(DEAD)') ? [...line.matchAll(deadTemplate)][0] : [...line.matchAll(damageTemplate)][0]; const data = line.includes('(DEAD)') ? [...line.matchAll(deadTemplate)][0] : [...line.matchAll(damageTemplate)][0];
if (!data) return stats; if (!data) return;
const info = { const info = {
time: data[1], time: data[1],
@@ -163,23 +157,21 @@ module.exports = {
attackerID: data[7] attackerID: data[7]
}; };
if (!client.exists(info.player) || !client.exists(info.playerID)) return stats; if (!client.exists(info.player) || !client.exists(info.playerID)) return;
let playerStat = stats.find(stat => stat.playerID == info.playerID); let playerStat = await client.dbo.collection("players").findOne({"playerID": info.playerID});
let playerStatIndex = stats.indexOf(playerStat); if (!client.exits(playerStat)) playerStat = getDefaultPlayer(info.player, info.playerID);
if (playerStat === undefined) playerStat = getDefaultPlayerStats(info.player, info.playerID);
playerStat.lastDamageDate = await client.getDateEST(info.time); playerStat.lastDamageDate = await client.getDateEST(info.time);
playerStat.lastHitBy = info.attacker; playerStat.lastHitBy = info.attacker;
if (playerStatIndex === -1) stats.push(playerStat); return await UpdatePlayer(client, playerStat);
else stats[playerStatIndex] = playerStat;
} }
return stats; return;
}, },
HandleActivePlayersList: async (client, guildId) => { HandleActivePlayersList: async (client, guild) => {
client.activePlayersTick = 0; // reset hour tick client.activePlayersTick = 0; // reset hour tick
const data = await FetchServerSettings(client, 'HandleActivePlayersList'); // Fetch server status const data = await FetchServerSettings(client, 'HandleActivePlayersList'); // Fetch server status
@@ -207,12 +199,10 @@ module.exports = {
statusText = "Unknown Status"; statusText = "Unknown Status";
} }
let guild = await client.GetGuild(guildId);
if (!client.exists(guild.playerstats)) guild.playerstats = [];
if (!client.exists(guild.activePlayersChannel)) return; if (!client.exists(guild.activePlayersChannel)) return;
const channel = client.GetChannel(guild.activePlayersChannel); const channel = client.GetChannel(guild.activePlayersChannel);
let activePlayers = guild.playerstats.filter(p => p.connected === true); let activePlayers = client.dbo.collection("players").find({"connected": true})
let des = ``; let des = ``;
for (let i = 0; i < activePlayers.length; i++) { for (let i = 0; i < activePlayers.length; i++) {