interface TServer { ip: string code: string } import Discord from 'discord.js'; import TClient from '../client.js'; import FormatPlayer from '../helpers/FormatPlayer.js'; import Logger from '../helpers/Logger.js'; import {writeFileSync, readFileSync} from 'node:fs'; import {FSPlayer, FSData, FSCareerSavegame} from '../typings/interfaces'; export default async(client:TClient, Channel:string, Message:string, Server:TServer, ServerName:string)=>{ let playerData:Array = []; const msg = await (client.channels.resolve(Channel) as Discord.TextChannel).messages.fetch(Message); const serverErrorEmbed = new client.embed().setColor(client.config.embedColorRed).setTitle('Host did not respond back in time'); const genericEmbed = new client.embed(); let sessionInit = {signal: AbortSignal.timeout(8500),headers:{'User-Agent':'Daggerbot - HITALL/undici'}}; try { const hitDSS = await fetch(Server.ip+'/feed/dedicated-server-stats.json?code='+Server.code, sessionInit).then(r=>r.json() as Promise); const hitCSG = await fetch(Server.ip+'/feed/dedicated-server-savegame.html?code='+Server.code+'&file=careerSavegame', sessionInit).then(async r=>(client.xjs.xml2js(await r.text(), {compact: true}) as any).careerSavegame as FSCareerSavegame); if (!hitDSS ?? !hitCSG){ if (hitDSS && !hitDSS.slots) return Logger.forwardToConsole('log', 'MPModule', `DSS failed with unknown slots table for ${client.MPServerCache[ServerName].name}`); else return msg.edit({embeds: [serverErrorEmbed]}); } // Truncate unnecessary parts of the name for the MPServerCache // This is a mess, but it works. for (const filter of ['Official Daggerwin Game Server', 'Daggerwin Multifarm']) { if (hitDSS.server?.name === undefined) return; if (hitDSS.server?.name.includes(filter)) client.MPServerCache[ServerName].name = ['Daggerwin', 'DagMF'][['Official Daggerwin Game Server', 'Daggerwin Multifarm'].indexOf(filter)]; } //Timescale formatting function formatTimescale(number:number,digits:number,icon:string){ var n = Number(number); return n.toLocaleString(undefined, {minimumFractionDigits: digits})+icon } // Join/Leave log function playerLogEmbed(player:FSPlayer,joinLog:boolean){ const logEmbed = new client.embed().setDescription(`**${player.name}${FormatPlayer.decoratePlayerIcons(player)}** ${joinLog ? 'joined' : 'left'} **${client.MPServerCache[ServerName].name}** at `); if (joinLog) return logEmbed.setColor(client.config.embedColorGreen); else if (player.uptime > 0) return logEmbed.setColor(client.config.embedColorRed).setFooter({text:`Farmed for ${FormatPlayer.uptimeFormat(player.uptime)}`}); else return logEmbed.setColor(client.config.embedColorRed); } const serverLog = client.channels.resolve(client.config.mainServer.channels.fs_server_log) as Discord.TextChannel; const playersOnServer = hitDSS.slots?.players.filter(x=>x.isUsed); const playersInCache = client.MPServerCache[ServerName].players; if (!playersOnServer ?? playersOnServer === undefined) return Logger.forwardToConsole('log', 'MPModule', 'Array is empty, ignoring...'); // For the love of god, stop throwing errors everytime. playersOnServer.forEach(player=>playerData.push(`**${player.name}${FormatPlayer.decoratePlayerIcons(player)}**\nFarming for ${FormatPlayer.uptimeFormat(player.uptime)}`)); // Player leaving for (const player of playersInCache.filter(x=>!playersOnServer.some(y=>y.name === x.name))){ if (player.uptime > 0) serverLog.send({embeds:[playerLogEmbed(player,false)]}); } // Player joining let playerObject; if (!playersInCache.length && client.uptime > 32010) playerObject = playersOnServer; if (playerObject) for (const player of playerObject) serverLog.send({embeds:[playerLogEmbed(player,true)]}); else if (playersInCache.length) playerObject = playersOnServer.filter(x=>!playersInCache.some(y=>y.name === x.name)); if (client.MPServerCache[ServerName].name === null) return; const Database:Array = JSON.parse(readFileSync(`src/database/${client.MPServerCache[ServerName].name}PlayerData.json`,{encoding:'utf8',flag:'r+'})); Database.push(hitDSS.slots?.used); writeFileSync(`src/database/${client.MPServerCache[ServerName].name}PlayerData.json`, JSON.stringify(Database)); client.MPServerCache[ServerName].players = playersOnServer; if (hitDSS.server.name.length < 1) { msg.edit({content: 'This embed will resume when server is back online.', embeds: [genericEmbed.setColor(client.config.embedColorRed).setTitle('The server seems to be offline.')]}); client.MPServerCache[ServerName].status = 'offline' } else { client.MPServerCache[ServerName].status = 'online'; const serverDetails = new client.embed().setColor(client.config.embedColor).setTitle('Server details').setFields( {name: 'Current map', value: hitDSS.server.mapName, inline: true}, {name: 'Server version', value: hitDSS.server.version, inline: true}, {name: 'In-game Time', value: `${('0'+Math.floor((hitDSS.server.dayTime/3600/1000))).slice(-2)}:${('0'+Math.floor((hitDSS.server.dayTime/60/1000)%60)).slice(-2)}`, inline: true}, {name: 'Slot Usage', value: isNaN(Number(hitCSG?.slotSystem?._attributes.slotUsage)) === true ? 'Unavailable' : Number(hitCSG.slotSystem?._attributes.slotUsage).toLocaleString('en-us'), inline: true}, {name: 'Autosave Interval', value: isNaN(Number(hitCSG?.settings?.autoSaveInterval._text)) === true ? 'Unavailable' : Number(hitCSG.settings?.autoSaveInterval._text).toFixed(0)+' mins', inline:true}, {name: 'Timescale', value: isNaN(Number(hitCSG?.settings?.timeScale._text)) === true ? 'Unavailable' : formatTimescale(Number(hitCSG.settings?.timeScale._text), 0, 'x'), inline: true} ); const playersEmbed = new client.embed().setColor(client.config.embedColor).setTitle(hitDSS.server.name).setDescription(hitDSS.slots.used < 1 ? '*No players online*' : playerData.join('\n\n')).setAuthor({name:`${hitDSS.slots.used}/${hitDSS.slots.capacity}`}); msg.edit({content:'This embed updates every 35 seconds.',embeds:[serverDetails, playersEmbed]}); } } catch(err) { msg.edit({content: err.message, embeds: [serverErrorEmbed]}); Logger.forwardToConsole('log', 'MPModule', `Failed to make a request for ${ServerName}: ${err.message}`); } }