2023-09-01 00:32:11 -04:00
interface TServer {
ip : string
code : string
}
2023-05-05 18:41:35 -04:00
import Discord from 'discord.js' ;
2023-09-03 00:15:02 -04:00
import TClient from '../client.js' ;
2023-08-30 04:34:59 -04:00
import FormatPlayer from '../helpers/FormatPlayer.js' ;
2023-09-29 17:27:32 -04:00
import Logger from '../helpers/Logger.js' ;
2023-10-07 04:48:39 -04:00
import HookMgr from './HookManager.js' ;
2023-05-23 01:14:17 -04:00
import { writeFileSync , readFileSync } from 'node:fs' ;
2023-09-01 00:32:11 -04:00
import { FSPlayer , FSData , FSCareerSavegame } from '../typings/interfaces' ;
2023-05-05 18:41:35 -04:00
2023-08-19 08:50:05 -04:00
export default async ( client :TClient , Channel :string , Message :string , Server :TServer , ServerName :string ) = > {
let playerData :Array < string > = [ ] ;
2023-10-07 17:01:16 -04:00
let dataUnavailable = 'Unavailable'
2023-08-18 07:18:33 -04:00
const msg = await ( client . channels . resolve ( Channel ) as Discord . TextChannel ) . messages . fetch ( Message ) ;
2023-08-19 08:50:05 -04:00
const serverErrorEmbed = new client . embed ( ) . setColor ( client . config . embedColorRed ) . setTitle ( 'Host did not respond back in time' ) ;
const genericEmbed = new client . embed ( ) ;
2023-10-07 04:48:39 -04:00
const refreshIntervalText = 'Refreshes every 35 seconds.' ;
2023-10-05 07:57:07 -04:00
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 < FSData > ) ;
2023-10-07 17:01:16 -04:00
const hitCSG = await fetch ( Server . ip + '/feed/dedicated-server-savegame.html?code=' + Server . code + '&file=careerSavegame' , sessionInit ) . then ( async r = > ( new client . fxp . XMLParser ( { ignoreAttributes : false , transformAttributeName ( attributeName ) { return attributeName . replaceAll ( '@_' , '' ) } } ) . parse ( await r . text ( ) ) as any ) . careerSavegame as FSCareerSavegame ) ;
2023-08-18 20:54:17 -04:00
2023-10-05 07:57:07 -04:00
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 ] } ) ;
}
2023-08-18 20:54:17 -04:00
2023-10-05 07:57:07 -04:00
// 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 ) ] ;
}
2023-08-19 20:17:22 -04:00
2023-10-05 07:57:07 -04:00
//Timescale formatting
function formatTimescale ( number : number , digits :number , icon :string ) {
var n = Number ( number ) ;
return n . toLocaleString ( undefined , { minimumFractionDigits : digits } ) + icon
}
2023-08-15 06:47:31 -04:00
2023-10-05 07:57:07 -04:00
// 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 <t: ${ Math . round ( Date . now ( ) / 1000 ) } :t> ` ) ;
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 ) ;
}
2023-05-07 04:41:20 -04:00
2023-10-05 07:57:07 -04:00
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 ) } ` ) ) ;
2023-08-24 12:06:39 -04:00
2023-10-05 07:57:07 -04:00
// 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 ) ) ;
2023-08-24 12:06:39 -04:00
2023-10-05 07:57:07 -04:00
if ( client . MPServerCache [ ServerName ] . name === null ) return ;
const Database :Array < number > = 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 ;
2023-08-19 08:50:05 -04:00
2023-10-05 07:57:07 -04:00
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 (
2023-10-12 07:34:00 -04:00
{ name : 'Current map' , value : hitDSS?.server?.mapName === undefined ? dataUnavailable : hitDSS.server.mapName , inline : true } ,
{ name : 'Server version' , value : hitDSS?.server?.version === undefined ? dataUnavailable : hitDSS.server.version , inline : true } ,
2023-10-05 07:57:07 -04:00
{ 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 } ,
2023-10-07 17:01:16 -04:00
{ name : 'Slot Usage' , value : isNaN ( Number ( hitCSG ? . slotSystem ? . slotUsage ) ) === true ? dataUnavailable : Number ( hitCSG . slotSystem ? . slotUsage ) . toLocaleString ( 'en-us' ) , inline : true } ,
{ name : 'Autosave Interval' , value : isNaN ( Number ( hitCSG ? . settings ? . autoSaveInterval ) ) === true ? dataUnavailable : Number ( hitCSG . settings ? . autoSaveInterval ) . toFixed ( 0 ) + ' mins' , inline :true } ,
{ name : 'Timescale' , value : isNaN ( Number ( hitCSG ? . settings ? . timeScale ) ) === true ? dataUnavailable : formatTimescale ( Number ( hitCSG . settings ? . timeScale ) , 0 , 'x' ) , inline : true }
2023-10-05 07:57:07 -04:00
) ;
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 } ` } ) ;
2023-10-07 04:48:39 -04:00
msg . edit ( { content :refreshIntervalText , embeds : [ serverDetails , playersEmbed ] } ) ;
2023-08-19 08:50:05 -04:00
}
2023-10-07 04:48:39 -04:00
// #multifarm_chat webhook
const growthModeTextMap = {
'1' : 'Yes' ,
'2' : 'No' ,
'3' : 'Growth paused'
}
2023-10-07 17:01:16 -04:00
const growthModeText = growthModeTextMap [ hitCSG ? . settings . growthMode ] ? ? dataUnavailable ;
2023-10-07 04:48:39 -04:00
function genericMapping < T > ( map : Record < string , T > , key : string , defaultValue : T ) : T {
return map [ key ] ? ? defaultValue ;
}
const genericTextMap = {
'false' : 'Off' ,
'true' : 'On'
}
const fuelUsageTextMap = {
'1' : 'Low' ,
'2' : 'Normal' ,
'3' : 'High'
}
2023-10-07 17:01:16 -04:00
const fuelUsageText = fuelUsageTextMap [ hitCSG ? . settings . fuelUsage ] ? ? dataUnavailable ;
2023-10-07 04:48:39 -04:00
const dirtIntervalTextMap = {
'1' : 'Off' ,
'2' : 'Slow' ,
'3' : 'Normal' ,
'4' : 'Fast'
}
2023-10-07 17:01:16 -04:00
const dirtIntervalText = dirtIntervalTextMap [ hitCSG ? . settings . dirtInterval ] ? ? dataUnavailable ;
2023-10-07 04:48:39 -04:00
// Edit the embed in #multifarm_chat
HookMgr . edit ( client , 'mf_chat' , '1159998634604109897' , '1160098458997370941' , {
content : refreshIntervalText ,
embeds : [ new client . embed ( ) . setColor ( client . config . embedColor ) . setTitle ( 'Savegame Settings' ) . addFields (
{ name : 'Seasonal Growth' , value : growthModeText , inline : true } ,
2023-10-07 17:01:16 -04:00
{ name : 'Crop Destruction' , value : genericMapping ( genericTextMap , hitCSG ? . settings . fruitDestruction , dataUnavailable ) , inline : true } ,
{ name : 'Periodic Plowing' , value : genericMapping ( genericTextMap , hitCSG ? . settings . plowingRequiredEnabled , dataUnavailable ) , inline : true } ,
{ name : 'Stones' , value : genericMapping ( genericTextMap , hitCSG ? . settings . stonesEnabled , dataUnavailable ) , inline : true } ,
{ name : 'Lime' , value : genericMapping ( genericTextMap , hitCSG ? . settings . limeRequired , dataUnavailable ) , inline : true } ,
{ name : 'Weeds' , value : genericMapping ( genericTextMap , hitCSG ? . settings . weedsEnabled , dataUnavailable ) , inline : true } ,
2023-10-07 04:48:39 -04:00
{ name : 'Fuel Usage' , value : fuelUsageText , inline : true } ,
{ name : 'Dirt Interval' , value : dirtIntervalText , inline : true } ,
) . setFooter ( { text : 'Last updated' } ) . setTimestamp ( ) ]
} ) ;
2023-10-05 07:57:07 -04:00
} catch ( err ) {
msg . edit ( { content : err.message , embeds : [ serverErrorEmbed ] } ) ;
Logger . forwardToConsole ( 'log' , 'MPModule' , ` Failed to make a request for ${ ServerName } : ${ err . message } ` ) ;
2023-05-05 18:41:35 -04:00
}
}