diff --git a/src/MPLoop.ts b/src/MPLoop.ts index 0c7f182..abdbfd7 100644 --- a/src/MPLoop.ts +++ b/src/MPLoop.ts @@ -1,21 +1,16 @@ import Discord from 'discord.js'; import TClient from './client'; import fs from 'node:fs'; -import {FSData, FSCareerSavegame} from './typings/interfaces'; +import {FSPlayer, FSData, FSCareerSavegame} from './typings/interfaces'; -export default async(client:TClient,Channel:string,Message:string)=>{ +export default async(client:TClient,Channel:string,Message:string,ServerName:string)=>{ if (!client.config.botSwitches.mpstats) return; const msg = await (client.channels.resolve(Channel) as Discord.TextChannel).messages.fetch(Message); const embed = new client.embed(); - let Players = []; + let playerData:Array = []; let error:Boolean; - + let isServerOnline = false; const Server = await client.MPServer._content.findById(client.config.mainServer.id); - const FS_IP = Server.ip; - const FS_Code = Server.code; - const verifyUrl = FS_IP.match(/http|https/); - const DSSUrl = FS_IP+'/feed/dedicated-server-stats.json?code='+FS_Code; - const CSGUrl = FS_IP+'/feed/dedicated-server-savegame.html?code='+FS_Code+'&file=careerSavegame'; const DSS = { data: {} as FSData, fetchResult: '' as string @@ -24,11 +19,11 @@ export default async(client:TClient,Channel:string,Message:string)=>{ data: {} as FSCareerSavegame, fetchResult: '' as string }; - if (!verifyUrl) return msg.edit({content: '*Detected an invalid IP\nContact MP Manager or Bot Tech*', embeds: null}); + if (!Server.ip.match(/http|https/)) return msg.edit({content: '*Detected an invalid IP\nContact MP Manager or Bot Tech*', embeds: null}); async function serverData(client:TClient, URL:string){ return await client.axios.get(URL, {timeout: 5000, maxContentLength: Infinity, headers:{'User-Agent':`Daggerbot/axios ${client.axios.VERSION}`}}).catch((error:Error)=>error.message) } - await Promise.all([serverData(client, DSSUrl), serverData(client, CSGUrl)]).then(function(results){ + await Promise.all([serverData(client, Server.ip+'/feed/dedicated-server-stats.json?code='+Server.code), serverData(client, Server.ip+'/feed/dedicated-server-savegame.html?code='+Server.code+'&file=careerSavegame')]).then(function(results){ if (typeof results[0] === 'string'){ DSS.fetchResult = `DagMP DSS failed, ${results[0]}`; embed.addFields({name:'DSS Status',value:results[0]}) @@ -61,20 +56,49 @@ export default async(client:TClient,Channel:string,Message:string)=>{ return; } - const Database = JSON.parse(fs.readFileSync('src/database/MPPlayerData.json',{encoding:'utf8',flag:'r+'})); - Database.push(DSS.data.slots?.used); - fs.writeFileSync('src/database/MPPlayerData.json', JSON.stringify(Database)); - //Timescale formatting function formatTimescale(number:number,digits:number,icon:string){ var n = Number(number); return n.toLocaleString(undefined, {minimumFractionDigits: digits})+icon } - + // Join/Leave log - Dorime to tae for examples :dorime: + function playerLogEmbed(player:FSPlayer,joinLog:boolean){ + const logEmbed = new client.embed().setDescription(`**${player.name} ${player.isAdmin ? '| admin' : ''}** ${joinLog ? 'joined' : 'left'} **${ServerName}** at `); + if (joinLog) return logEmbed.setColor(client.config.embedColorGreen); + else return logEmbed.setColor(client.config.embedColorRed) + } + function playerLog(){ + // Player leaving + playersInCache.filter(x=>!playersOnServer.some(y=>y.name === x.name)).forEach(player=>serverLog.send({embeds:[playerLogEmbed(player,false)]})); + // Player joining + let playerObject; + if (playersInCache.length === 0 && (client.uptime as number) > 60010) playerObject = playersOnServer; + else if (playersInCache.length !== 0) playerObject = playersOnServer.filter(x=>!playersInCache.some(y=>y.name === x.name)); + if (playerObject) playerObject.forEach(x=>serverLog.send({embeds:[playerLogEmbed(x,true)]})); + } + + const serverIndicatorEmbed =(indicator:string)=>new client.embed().setTitle(`**${ServerName}** is now ${indicator}`).setColor(client.config.embedColorOrange).setTimestamp(); + + const serverLog = client.channels.resolve(client.config.mainServer.channels.fs_server_log) as Discord.TextChannel; + const playersOnServer = DSS.data.slots.players.filter(x=>x.isUsed); + const playersInCache = client.MPServerCache.players; + playersOnServer.forEach(player=>playerData.push(`**${player.name} ${player.isAdmin ? '| admin' : ''}**\nFarming for ${client.formatPlayerUptime(player.uptime)}`)); + + ServerName = client.MPServerCache.name; + if (DSS.data.server.name === 'Official Daggerwin Game Server') client.MPServerCache.name = 'Daggerwin'; + else client.MPServerCache.name = 'Dag - YT Series'; + if (DSS.data.server.name.length === 0){ embed.setTitle('The server seems to be offline.').setColor(client.config.embedColorRed); - msg.edit({content: 'This embed will resume when the server is back online.', embeds: [embed]}) + msg.edit({content: 'This embed will resume when the server is back online.', embeds: [embed]}); + if (client.MPServerCache.status === 'online') serverLog.send({embeds:[serverIndicatorEmbed('offline')]}); + client.MPServerCache.status = 'offline'; } else { + if (client.MPServerCache.status === 'offline'){ + serverLog.send({embeds:[serverIndicatorEmbed('online')]}); + isServerOnline = true + }; + client.MPServerCache.status = 'online'; const statusEmbed = new client.embed().setColor(client.config.embedColor).setTitle('Server details').setFields( {name: 'Current Map', value: `${DSS.data.server.mapName.length === 0 ? '\u200b' : DSS.data.server.mapName}`, inline: true}, {name: 'Version', value: `${DSS.data.server.version.length === 0 ? '\u200b' : DSS.data.server.version}`, inline: true}, @@ -82,8 +106,15 @@ export default async(client:TClient,Channel:string,Message:string)=>{ {name: 'Slot Usage', value: `${isNaN(Number(CSG.data.slotSystem?._attributes.slotUsage)) === true ? 'Unavailable' : Number(CSG.data.slotSystem?._attributes.slotUsage).toLocaleString('en-us')}`, inline: true}, {name: 'Timescale', value: `${isNaN(Number(CSG.data.settings?.timeScale._text)) === true ? 'Unavailable' : formatTimescale(Number(CSG.data.settings?.timeScale._text), 0, 'x')}`, inline: true} ); - DSS.data.slots.players.filter(x=>x.isUsed !== false).forEach(player=>Players.push(`**${player.name} ${player.isAdmin ? '| admin' : ''}**\nFarming for ${(Math.floor(player.uptime/60))} hr & ${(''+(player.uptime%60)).slice(-2)} min`)); - embed.setColor(client.config.embedColor).setTitle(DSS.data.server.name).setDescription(`${DSS.data.slots.used === 0 ? '*No players online*' : Players.join('\n\n')}`).setAuthor({name:`${DSS.data.slots.used}/${DSS.data.slots.capacity}`}); - msg.edit({content:'This embed updates every minute.',embeds:[statusEmbed,embed]}) + embed.setColor(client.config.embedColor).setTitle(DSS.data.server.name).setDescription(`${DSS.data.slots.used === 0 ? '*No players online*' : playerData.join('\n\n')}`).setAuthor({name:`${DSS.data.slots.used}/${DSS.data.slots.capacity}`}); + msg.edit({content:'This embed updates every minute.',embeds:[statusEmbed,embed]}); + } + + if (!isServerOnline){ + playerLog(); + const Database:Array = JSON.parse(fs.readFileSync('src/database/MPPlayerData.json',{encoding:'utf8',flag:'r+'})); + Database.push(DSS.data.slots?.used); + fs.writeFileSync('src/database/MPPlayerData.json', JSON.stringify(Database)); + client.MPServerCache.players = playersOnServer } } diff --git a/src/client.ts b/src/client.ts index e286aaf..c49c8a2 100644 --- a/src/client.ts +++ b/src/client.ts @@ -1,8 +1,8 @@ -import Discord, { Client, WebhookClient, GatewayIntentBits, Partials } from 'discord.js'; +import Discord, {Client, WebhookClient, GatewayIntentBits, Partials} from 'discord.js'; import fs from 'node:fs'; import {exec} from 'node:child_process'; import mongoose from 'mongoose'; -import {formatTimeOpt, Tokens, Config, repeatedMessages} from './typings/interfaces'; +import {formatTimeOpt, Tokens, Config, repeatedMessages, MPServerCache} from './typings/interfaces'; import bannedWords from './models/bannedWords.js'; import userLevels from './models/userLevels.js'; import suggestion from './models/suggestion.js'; @@ -43,6 +43,7 @@ export default class TClient extends Client { bonkCount: bonkCount; bannedWords: bannedWords; MPServer: MPServer; + MPServerCache: MPServerCache; suggestion: suggestion; repeatedMessages: repeatedMessages; statsGraph: number; @@ -80,6 +81,7 @@ export default class TClient extends Client { this.punishments = new punishments(this); this.bannedWords = new bannedWords(this); this.MPServer = new MPServer(this); + this.MPServerCache = {players: [], status: null, name: undefined} as MPServerCache; this.suggestion = new suggestion(this); this.repeatedMessages = {}; this.setMaxListeners(20); @@ -96,7 +98,7 @@ export default class TClient extends Client { socketTimeoutMS: 30000, family: 4 }).then(()=>console.log(this.logTime(), 'Successfully connected to MongoDB')).catch(err=>{console.error(this.logTime(), `Failed to connect to MongoDB\n${err.reason}`); exec('pm2 stop Daggerbot')}) - this.login(this.tokens.main); + this.login(this.tokens.beta); for await (const file of fs.readdirSync('dist/events')){ const eventFile = await import(`./events/${file}`); this.on(file.replace('.js',''), async(...args)=>eventFile.default.run(this,...args)) @@ -137,6 +139,18 @@ export default class TClient extends Client { } } return text.trim(); } + formatPlayerUptime(oldTime:number){ + var Hours=0; + oldTime=Math.floor(Number(oldTime)); + if(oldTime>=60){ + var Hours=Math.floor(Number(oldTime)/60); + var Minutes=(Number(oldTime)-(Hours*60)); + } else Minutes=Number(oldTime) + if(Hours>=24){ + var Days=Math.floor(Number(Hours)/24); + var Hours=(Hours-(Days*24)); + } return (Days>0?Days+' d ':'')+(Hours>0?Hours+' h ':'')+(Minutes>0?Minutes+' m':'') + } isStaff = (guildMember:Discord.GuildMember)=>this.config.mainServer.staffRoles.map((x: string)=>this.config.mainServer.roles[x]).some((x: string)=>guildMember.roles.cache.has(x)); youNeedRole = (interaction:Discord.CommandInteraction, role:string)=>interaction.reply(`This command is restricted to <@&${this.config.mainServer.roles[role]}>`); @@ -151,21 +165,22 @@ export default class TClient extends Client { } else text = text + emptyChar.repeat(length - text.length); return text; } - async punish(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>, type: string){ - if (!client.isStaff(interaction.member as Discord.GuildMember)) return client.youNeedRole(interaction, "dcmod"); + async punish(interaction: Discord.ChatInputCommandInteraction<'cached'>, type: string){ + if (!this.isStaff(interaction.member as Discord.GuildMember)) return this.youNeedRole(interaction, "dcmod"); const time = interaction.options.getString('time') ?? undefined; const reason = interaction.options.getString('reason') ?? 'Reason unspecified'; const GuildMember = interaction.options.getMember('member') ?? undefined; const User = interaction.options.getUser('member', true); - - console.log(client.logTime(), `[PunishmentLog] ${GuildMember.user.tag ?? User.tag ?? 'No user data'} and ${time ?? 'no duration set'} was used in /${interaction.commandName} for ${reason}`); + + console.log(this.logTime(), `[PunishmentLog] ${GuildMember.user.tag ?? User.tag ?? 'No user data'} ${time ? ['warn', 'kick'].includes(this.punishments.type) ? 'and no duration set' : `and ${time} (duration)` : ''} was used in /${interaction.commandName} for ${reason}`); + (this.channels.cache.get(this.config.mainServer.channels.punishment_log) as Discord.TextChannel).send({embeds:[new this.embed().setColor(this.config.embedColor).setTitle('Punishment Log').setDescription(`${GuildMember.user.tag ?? User.tag ?? 'No user data'} ${time ? ['warn', 'kick'].includes(this.punishments.type) ? 'and no duration set' : `and ${time} (duration)` : ''} was used in \`/${interaction.commandName}\` for \`${reason}\``).setTimestamp()]}); if (interaction.user.id == User.id) return interaction.reply(`You cannot ${type} yourself.`); if (!GuildMember && type != 'ban') return interaction.reply(`You cannot ${type} someone who is not in the server.`); if (User.bot) return interaction.reply(`You cannot ${type} a bot!`); await interaction.deferReply(); - await client.punishments.addPunishment(type, { time, interaction }, interaction.user.id, reason, User, GuildMember); + await this.punishments.addPunishment(type, { time, interaction }, interaction.user.id, reason, User, GuildMember); } async YTLoop(YTChannelID: string, YTChannelName: string, DCChannelID: string){ let Data:any; diff --git a/src/commands/ban.ts b/src/commands/ban.ts index a9012db..530b345 100644 --- a/src/commands/ban.ts +++ b/src/commands/ban.ts @@ -2,7 +2,7 @@ import Discord,{SlashCommandBuilder} from 'discord.js'; import TClient from '../client.js'; export default { run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){ - client.punish(client, interaction, 'ban'); + client.punish(interaction, 'ban'); }, data: new SlashCommandBuilder() .setName('ban') diff --git a/src/commands/kick.ts b/src/commands/kick.ts index 8eac9ad..eb990b3 100644 --- a/src/commands/kick.ts +++ b/src/commands/kick.ts @@ -2,7 +2,7 @@ import Discord,{SlashCommandBuilder} from 'discord.js'; import TClient from '../client.js'; export default { run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){ - client.punish(client, interaction, 'kick'); + client.punish(interaction, 'kick'); }, data: new SlashCommandBuilder() .setName('kick') diff --git a/src/commands/mp.ts b/src/commands/mp.ts index e6523fd..aeb1c25 100644 --- a/src/commands/mp.ts +++ b/src/commands/mp.ts @@ -8,18 +8,14 @@ async function MPdata(client:TClient, interaction:Discord.ChatInputCommandIntera let FSserver; if (!await client.MPServer._content.findOne({_id:interaction.guildId})) return interaction.reply('This server isn\'t linked to the bot.'); const ServerURL = await client.MPServer._content.findById(interaction.guildId); - if (!ServerURL) return interaction.reply(`No FS server found, please notify <@&${client.config.mainServer.roles.mpmanager}> to add it.`) - const MPURL = ServerURL.ip - const MPCode = ServerURL.code - const verifyURL = MPURL.match(/http|https/) - const completedURL = MPURL+'/feed/dedicated-server-stats.json?code='+MPCode - if (!verifyURL) return interaction.reply(`The server IP for this server is currently invalid, please notify <@&${client.config.mainServer.roles.mpmanager}>`) + if (!ServerURL) return interaction.reply(`No FS server found, please notify <@&${client.config.mainServer.roles.mpmanager}> to add it.`); + if (!ServerURL.ip.match(/http|https/)) return interaction.reply(`The server IP for this server is currently invalid, please notify <@&${client.config.mainServer.roles.mpmanager}>`); // Fetch dss - try { // v I am aware timeout has decreased from 2800 to 2588 to fit within Discord's interaction timeouts (3s) -Toast - FSserver = await client.axios.get(completedURL, {timeout: 2588, headers: {'User-Agent': `Daggerbot - mp cmd/axios ${client.axios.VERSION}`}}) + try {// I am aware timeout has decreased from 2800 to 2588 to fit within Discord's interaction timeouts (3s) -Toast + FSserver = await client.axios.get(ServerURL.ip+'/feed/dedicated-server-stats.json?code='+ServerURL.code, {timeout: 2588, headers: {'User-Agent': `Daggerbot - mp cmd/axios ${client.axios.VERSION}`}}) } catch(err) { - // Blame Nawdic & RedRover92 + // Blame Nawdic embed.setTitle('Host is not responding.'); embed.setColor(client.config.embedColorRed); console.log(client.logTime(), 'DagMP failed to fetch, host didn\'t respond in time.'); @@ -79,16 +75,15 @@ export default { const Url = await client.MPServer._content.findById(interaction.guildId); if (Url.ip && Url.code) return interaction.reply(`${Url.get('ip')}`+'/feed/dedicated-server-stats.json?code='+`${Url.get('code')}`) } catch(err){ - console.log(`MPDB :: ${err}`) + console.log(`MPDB :: ${err}`); interaction.reply('**Database error:**\nTry inserting an URL first.') } }else{ - const verifyURL = address.match(/dedicated-server-stats/) - if (!verifyURL) return interaction.reply('The URL does not match `dedicated-server-stats.xml`') - const newURL = address.replace('xml','json').split('/feed/dedicated-server-stats.json?code=') + if (!address.match(/dedicated-server-stats/)) return interaction.reply('The URL does not match `dedicated-server-stats.xml`'); + const newURL = address.replace('xml','json').split('/feed/dedicated-server-stats.json?code='); try{ console.log(`MPDB :: URL for ${interaction.guild.name} has been updated by ${interaction.member.displayName} (${interaction.member.id})`); - await client.MPServer._content.create({_id: interaction.guildId, ip: newURL[0], code: newURL[1], timesUpdated: 0}) + await client.MPServer._content.create({_id: interaction.guildId, ip: newURL[0], code: newURL[1], timesUpdated: 0}); return interaction.reply('This server is now linked and URL has been added.'); } catch(err){ const affectedValues = await client.MPServer._content.findByIdAndUpdate({_id: interaction.guildId}, {ip: newURL[0], code: newURL[1]}); @@ -247,7 +242,7 @@ export default { embed1.setTitle(FSserver1?.data.server.name.length == 0 ? 'Offline' : FSserver1?.data.server.name) .setDescription(`${FSserver1?.data.slots.used}/${FSserver1?.data.slots.capacity}`) .setColor(FSserver1?.data.server.name.length == 0 ? client.config.embedColorRed : client.config.embedColor); - FSserver1?.data.slots.players.filter(x=>x.isUsed).forEach(player=>embed1.addFields({name: `${player.name} ${player.isAdmin ? '| admin' : ''}`, value: `Farming for ${(Math.floor(player.uptime/60))} hr, ${('0' + (player.uptime % 60)).slice(-2)} min`})) + FSserver1?.data.slots.players.filter(x=>x.isUsed).forEach(player=>embed1.addFields({name: `${player.name} ${player.isAdmin ? '| admin' : ''}`, value: `Farming for ${client.formatPlayerUptime(player.uptime)}`})) interaction.reply({embeds: [embed1], files: [Image]}) }/*, series: ()=>{ diff --git a/src/commands/mute.ts b/src/commands/mute.ts index 3469189..d44c35a 100644 --- a/src/commands/mute.ts +++ b/src/commands/mute.ts @@ -2,7 +2,7 @@ import Discord,{SlashCommandBuilder} from 'discord.js'; import TClient from '../client.js'; export default { run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){ - client.punish(client, interaction, 'mute'); + client.punish(interaction, 'mute'); }, data: new SlashCommandBuilder() .setName('mute') diff --git a/src/commands/softban.ts b/src/commands/softban.ts index 6abaab2..e39d5b0 100644 --- a/src/commands/softban.ts +++ b/src/commands/softban.ts @@ -2,7 +2,7 @@ import Discord,{SlashCommandBuilder} from 'discord.js'; import TClient from '../client.js'; export default { run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){ - client.punish(client, interaction, 'softban'); + client.punish(interaction, 'softban'); }, data: new SlashCommandBuilder() .setName('softban') diff --git a/src/commands/unpunish.ts b/src/commands/unpunish.ts index 9f90366..5f50065 100644 --- a/src/commands/unpunish.ts +++ b/src/commands/unpunish.ts @@ -9,6 +9,7 @@ export default { const reason = interaction.options.getString('reason') ?? 'Reason unspecified'; await client.punishments.removePunishment(punishment.id, interaction.user.id, reason, interaction); console.log(client.logTime(), `[UnpunishmentLog] Case #${interaction.options.getInteger('case_id')} was used in /${interaction.commandName} for ${reason}`); + (client.channels.cache.get(client.config.mainServer.channels.punishment_log) as Discord.TextChannel).send({embeds:[new client.embed().setColor(client.config.embedColor).setTitle('Unpunishment Log').setDescription(`Case #${interaction.options.getInteger('case_id')} was used in \`/${interaction.commandName}\` for \`${reason}\``).setTimestamp()]}); }, data: new SlashCommandBuilder() .setName('unpunish') diff --git a/src/commands/warn.ts b/src/commands/warn.ts index f764b7f..b0b56d2 100644 --- a/src/commands/warn.ts +++ b/src/commands/warn.ts @@ -2,7 +2,7 @@ import Discord,{SlashCommandBuilder} from 'discord.js'; import TClient from '../client.js'; export default { run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){ - client.punish(client, interaction, 'warn'); + client.punish(interaction, 'warn'); }, data: new SlashCommandBuilder() .setName('warn') diff --git a/src/config.json b/src/config.json index 5427bf5..9532250 100644 --- a/src/config.json +++ b/src/config.json @@ -2,6 +2,7 @@ "embedColor": "#0052cf", "embedColorBackup": "#0052cf", "embedColorGreen": "#57f287", + "embedColorOrange": "#cc5210", "embedColorYellow": "#ffea00", "embedColorRed": "#e62c3b", "embedColorBCA": "#ff69b4", @@ -69,7 +70,9 @@ "logs": "548032776830582794", "welcome": "621134751897616406", "botcommands": "468888722210029588", - "bankick_log": "1048341961901363352" + "bankick_log": "1048341961901363352", + "fs_server_log": "1104632399771488317", + "punishment_log": "1102751034754998302" } } } diff --git a/src/index.ts b/src/index.ts index 68cd7f4..780517a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -36,7 +36,7 @@ process.on('error', (error: Error)=>DZ(error, 'process-error')); client.on('error', (error: Error)=>DZ(error, 'client-error')); // YouTube Upload notification and Daggerwin MP loop -setInterval(()=>MPLoop(client, client.config.MPStatsLocation.channel, client.config.MPStatsLocation.message), 60000); +setInterval(()=>MPLoop(client, client.config.MPStatsLocation.channel, client.config.MPStatsLocation.message, 'Daggerwin'), 60000); setInterval(async()=>{ client.YTLoop('UCQ8k8yTDLITldfWYKDs3xFg', 'Daggerwin', '528967918772551702'); // 528967918772551702 = #videos-and-streams client.YTLoop('UCguI73--UraJpso4NizXNzA', 'Machinery Restorer', '767444045520961567') // 767444045520961567 = #machinery-restorer diff --git a/src/models/MPServer.ts b/src/models/MPServer.ts index 420a82f..8d7e8b8 100644 --- a/src/models/MPServer.ts +++ b/src/models/MPServer.ts @@ -20,6 +20,5 @@ export default class MPServer extends Schema { const server = await this._content.findById(serverId) if (server) await this._content.findByIdAndUpdate(server, {timesUpdated: server.timesUpdated + 1}) else await this._content.create({_id:serverId, timesUpdated: 1}) - //console.log(`[${serverId}] :: timesUpdated value incremented`) } } diff --git a/src/models/punishments.ts b/src/models/punishments.ts index 166df9f..7578808 100644 --- a/src/models/punishments.ts +++ b/src/models/punishments.ts @@ -43,7 +43,7 @@ export default class punishments extends Schema { } // Send it off to specific Discord channel. (this.client.channels.cache.get(channel) as Discord.TextChannel).send({embeds:[embed]}); - }// hi tae --- hi --- hru? --- no answer ok + } getTense(type:string){// Get past tense form of punishment type, grammar yes return { ban: 'banned', @@ -117,7 +117,7 @@ export default class punishments extends Schema { const guild = this.client.guilds.cache.get(this.client.config.mainServer.id) as Discord.Guild; const auditLogReason = `${reason || 'Reason unspecified'} | Case #${punishment.id}`; const User = await this.client.users.fetch(punishment.member); - const GuildMember = await guild.members.fetch(punishment.member); + const GuildMember = await guild.members.fetch(punishment.member).catch(()=>null); let removePunishmentData:Punishment={type:`un${punishment.type}`, _id, cancels:punishment.id, member:punishment.member, reason, moderator, time:now}; let removePunishmentResult; diff --git a/src/typings/interfaces.d.ts b/src/typings/interfaces.d.ts index cf03170..b9e2b59 100644 --- a/src/typings/interfaces.d.ts +++ b/src/typings/interfaces.d.ts @@ -49,9 +49,9 @@ export interface FSServer { export interface FSslots { capacity: number, used: number, - players: Array + players: Array } -export interface FSPlayers { +export interface FSPlayer { isUsed: boolean, isAdmin: boolean, uptime: number, @@ -135,6 +135,7 @@ export interface Tokens { export interface Config { embedColor: Discord.ColorResolvable, embedColorGreen: Discord.ColorResolvable, + embedColorOrange: Discord.ColorResolvable, embedColorYellow: Discord.ColorResolvable, embedColorRed: Discord.ColorResolvable, embedColorBCA: Discord.ColorResolvable, @@ -148,6 +149,11 @@ export interface Config { whitelist: Array mainServer: mainServer } +export interface MPServerCache { + players: FSPlayer[], + status: 'online' | 'offline' | null, + name: string | undefined +} interface MPStatsLocation { channel: string, message: string @@ -188,5 +194,7 @@ interface mainServerChannels { logs: string, welcome: string, botcommands: string, - bankick_log: string + bankick_log: string, + fs_server_log: string, + punishment_log: string } \ No newline at end of file