1
0
mirror of https://github.com/toast-ts/Daggerbot-TS.git synced 2024-09-29 12:30:58 -04:00

Use Object literal lookups and add User-Agent

This commit is contained in:
AnxietyisReal 2023-02-10 08:45:52 +11:00
parent 73fe20f58f
commit 907ef308c7
7 changed files with 315 additions and 342 deletions

View File

@ -3,22 +3,20 @@ import TClient from 'src/client';
export default {
async run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){
if (!client.isStaff(interaction.member) && !client.config.eval.whitelist.includes(interaction.member.id)) return client.youNeedRole(interaction, 'admin')
const Sub = interaction.options.getSubcommand();
const word = interaction.options.getString('word');
switch(Sub){
case 'view':
interaction.reply({content: 'Here is a complete list of banned words!\n*You can open it with a web browser, e.g Chrome/Firefox/Safari, or you can use Visual Studio Code/Notepad++*', files: ['src/database/bannedWords.json'], ephemeral: true})
break;
case 'add':
({
add: ()=>{
if (client.bannedWords._content.includes(word)) return interaction.reply({content: `\`${word}\` is already added.`, ephemeral: true});
client.bannedWords.addData(word).forceSave();
interaction.reply(`Successfully added \`${word}\` to the list.`)
break;
case 'remove':
},
remove: ()=>{
if (client.bannedWords._content.includes(word) == false) return interaction.reply({content: `\`${word}\` doesn't exist on the list.`, ephemeral: true});
client.bannedWords.removeData(word, 0, 0).forceSave();
interaction.reply(`Successfully removed \`${word}\` from the list.`)
}
},
view: ()=>interaction.reply({content: 'Here is a complete list of banned words!\n*You can open it with a web browser, e.g Chrome/Firefox/Safari, or you can use Visual Studio Code/Notepad++*', files: ['src/database/bannedWords.json'], ephemeral: true})
} as any)[interaction.options.getSubcommand()]();
},
data: new SlashCommandBuilder()
.setName('bannedwords')

View File

@ -4,50 +4,48 @@ import { Punishment } from "src/typings/interfaces";
export default {
async run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){
if (!client.isStaff(interaction.member)) return client.youNeedRole(interaction, 'dcmod');
const Subb = interaction.options.getSubcommand();
const caseId = interaction.options.getInteger('id');
if (Subb == 'update'){
const reason = interaction.options.getString('reason')
client.punishments._content.find((x:Punishment)=>x.id==caseId).reason = reason;
client.punishments.forceSave();
const embed = new client.embed().setColor(client.config.embedColorGreen).setTitle('Case updated').setDescription(`Case #${caseId} has been successfully updated with new reason:\n\`${reason}\``);
await interaction.reply({embeds: [embed]})
} else if (Subb == 'view'){
const punishment = client.punishments._content.find((x:Punishment)=>x.id==caseId);
if (!punishment) return interaction.reply('Invalid case #');
const cancelledBy = punishment.expired ? client.punishments._content.find((x:Punishment)=>x.cancels==punishment.id) : null;
const cancels = punishment.cancels ? client.punishments._content.find((x:Punishment)=>x.id==punishment.cancels) : null;
const embed = new client.embed().setColor(client.config.embedColor).setTimestamp(punishment.time).setTitle(`${client.formatPunishmentType(punishment, client, cancels)} | Case #${punishment.id}`).addFields(
{name: '🔹 User', value: `<@${punishment.member}> \`${punishment.member}\``, inline: true},
{name: '🔹 Moderator', value: `<@${punishment.moderator}> \`${punishment.moderator}\``, inline: true},
{name: '\u200b', value: '\u200b', inline: true},
{name: '🔹 Reason', value: `\`${punishment.reason || 'Reason unspecified'}\``, inline: true})
if (punishment.duration){
embed.addFields({name: '🔹 Duration', value: client.formatTime(punishment.duration, 100)})
({
update: async()=>{
const reason = interaction.options.getString('reason');
client.punishments._content.find((x:Punishment)=>x.id==caseId).reason = reason;
client.punishments.forceSave();
await interaction.reply({embeds: [new client.embed().setColor(client.config.embedColorGreen).setTitle('Case updated').setDescription(`Case #${caseId} has been successfully updated with new reason:\n\`${reason}\``)]})
},
view: ()=>{
const punishment = client.punishments._content.find((x:Punishment)=>x.id==caseId);
if (!punishment) return interaction.reply('Invalid case #');
const cancelledBy = punishment.expired ? client.punishments._content.find((x:Punishment)=>x.cancels==punishment.id) : null;
const cancels = punishment.cancels ? client.punishments._content.find((x:Punishment)=>x.id==punishment.cancels) : null;
const embed = new client.embed().setColor(client.config.embedColor).setTimestamp(punishment.time).setTitle(`${client.formatPunishmentType(punishment, client, cancels)} | Case #${punishment.id}`).addFields(
{name: '🔹 User', value: `<@${punishment.member}> \`${punishment.member}\``, inline: true},
{name: '🔹 Moderator', value: `<@${punishment.moderator}> \`${punishment.moderator}\``, inline: true},
{name: '\u200b', value: '\u200b', inline: true},
{name: '🔹 Reason', value: `\`${punishment.reason || 'Reason unspecified'}\``, inline: true})
if (punishment.duration) embed.addFields({name: '🔹 Duration', value: client.formatTime(punishment.duration, 100)})
if (punishment.expired) embed.addFields({name: '🔹 Expired', value: `This case has been overwritten by case #${cancelledBy.id} for reason \`${cancelledBy.reason}\``})
if (punishment.cancels) embed.addFields({name: '🔹 Overwrites', value: `This case overwrites case #${cancels.id} with reason \`${cancels.reason}\``})
interaction.reply({embeds: [embed]});
},
member: ()=>{
// if caseid is user id, show their punishment history sorted by most recent.
const user = (interaction.options.getUser('user') as Discord.User);
if (user.bot) return interaction.reply(`<@${user.id}>'s punishment history cannot be viewed.`)
const punishment = client.punishments._content.find((x:Punishment)=>x.member===user.id);
if (!punishment) return interaction.reply(`<@${user.id}> has a clean record.`)
const cancels = punishment.cancels ? client.punishments._content.find((x:Punishment)=>x.id==punishment.cancels) : null;
const userPunishment = client.punishments._content.filter((x:Punishment)=>x.member==user.id).sort((a:Punishment,b:Punishment)=>a.time-b.time).map((punishment:Punishment)=>{
return {
name: `${client.formatPunishmentType(punishment, client, cancels)} | Case #${punishment.id}`,
value: `Reason: \`${punishment.reason}\`\n${punishment.duration ? `Duration: ${client.formatTime(punishment.duration, 3)}\n` : ''}Moderator: <@${punishment.moderator}>${punishment.expired ? `\nOverwritten by case #${client.punishments._content.find((x:Punishment)=>x.cancels==punishment.id).id}` : ''}${punishment.cancels ? `\nOverwrites case #${punishment.cancels}` : ''}`
}
});
// if caseid is not a punishment nor a user, failed
if (!userPunishment || userPunishment.length == 0) return interaction.reply('No punishments found for that case # or User ID');
const pageNum = interaction.options.getInteger('page') ?? 1;
return interaction.reply({embeds: [new client.embed().setColor(client.config.embedColor).setTitle(`${user.username}'s punishment history`).setDescription(`**ID:** \`${user.id}\``).setFooter({text: `${userPunishment.length} total punishments. Viewing page ${pageNum} out of ${Math.ceil(userPunishment.length/6)}.`}).addFields(userPunishment.slice((pageNum - 1) * 6, pageNum * 6))]});
}
if (punishment.expired) embed.addFields({name: '🔹 Expired', value: `This case has been overwritten by case #${cancelledBy.id} for reason \`${cancelledBy.reason}\``})
if (punishment.cancels) embed.addFields({name: '🔹 Overwrites', value: `This case overwrites case #${cancels.id} with reason \`${cancels.reason}\``})
interaction.reply({embeds: [embed]});
} else {
// if caseid is user id, show their punishment history sorted by most recent.
const user = (interaction.options.getUser('user') as Discord.User);
if (user.bot) return interaction.reply(`<@${user.id}>'s punishment history cannot be viewed.`)
const punishment = client.punishments._content.find((x:Punishment)=>x.member===user.id);
if (!punishment) return interaction.reply(`<@${user.id}> has a clean record.`)
const cancels = punishment.cancels ? client.punishments._content.find((x:Punishment)=>x.id==punishment.cancels) : null;
const userPunishment = client.punishments._content.filter((x:Punishment)=>x.member==user.id).sort((a:Punishment,b:Punishment)=>a.time-b.time).map((punishment:Punishment)=>{
return {
name: `${client.formatPunishmentType(punishment, client, cancels)} | Case #${punishment.id}`,
value: `Reason: \`${punishment.reason}\`\n${punishment.duration ? `Duration: ${client.formatTime(punishment.duration, 3)}\n` : ''}Moderator: <@${punishment.moderator}>${punishment.expired ? `\nOverwritten by case #${client.punishments._content.find((x:Punishment)=>x.cancels==punishment.id).id}` : ''}${punishment.cancels ? `\nOverwrites case #${punishment.cancels}` : ''}`
}
});
// if caseid is not a punishment nor a user, failed
if (!userPunishment || userPunishment.length == 0) return interaction.reply('No punishments found for that case # or User ID');
const pageNum = interaction.options.getInteger('page') ?? 1;
const embed = new client.embed().setColor(client.config.embedColor).setTitle(`${user.username}'s punishment history`).setDescription(`**ID:** \`${user.id}\``).setFooter({text: `${userPunishment.length} total punishments. Viewing page ${pageNum} out of ${Math.ceil(userPunishment.length/6)}.`}).addFields(userPunishment.slice((pageNum - 1) * 6, pageNum * 6));
return interaction.reply({embeds: [embed]});
}
} as any)[interaction.options.getSubcommand()]();
},
data: new SlashCommandBuilder()
.setName('case')

View File

@ -22,8 +22,8 @@ const removeUsername = (text: string)=>{
export default {
async run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>) {
if (!client.config.eval.whitelist.includes(interaction.user.id)) return client.youNeedRole(interaction, 'bottech');
switch (interaction.options.getSubcommand()){
case 'eval':
({
eval: async()=>{
if (!client.config.eval.allowed) return interaction.reply({content: 'Eval is disabled.', ephemeral: true});
const code = interaction.options.getString('code') as string;
let output = 'error';
@ -59,16 +59,8 @@ export default {
{name: 'Output', value: `\`\`\`${removeUsername(output).slice(0,1016)}\n\`\`\``}
);
interaction.reply({embeds: [embed]}).catch(()=>(interaction.channel as Discord.TextChannel).send({embeds: [embed]}));
break
case 'logs':
interaction.deferReply();
(client.channels.resolve(client.config.mainServer.channels.console) as Discord.TextChannel).send({content: `Uploaded the current console dump as of <t:${Math.round(Date.now()/1000)}:R>`, files: [`${process.env.pm2_home}/logs/Daggerbot-out-0.log`, `${process.env.pm2_home}/logs/Daggerbot-error-0.log`]}).then(()=>interaction.editReply('It has been uploaded to dev server.')).catch((e:Error)=>interaction.editReply(`\`${e.message}\``))
break
case 'restart':
client.userLevels.forceSave();
interaction.reply(`Uptime before restarting: **${client.formatTime(client.uptime as number, 3, {commas: true, longNames: true})}**`).then(()=>exec('pm2 restart Daggerbot'))
break
case 'update':
},
update: async()=>{
var githubRepo = {owner: 'AnxietyisReal', repo: 'Daggerbot-TS', ref: 'HEAD'}
const octokit = new Octokit({timeZone: 'Australia/NSW', userAgent: 'Daggerbot'})
const fetchCommitMsg = await octokit.repos.getCommit(githubRepo).then(x=>x.data.commit.message);
@ -83,12 +75,8 @@ export default {
setTimeout(()=>{clarkson.edit(`Commit: **${fetchCommitMsg}**\nCommit author: **${fetchCommitAuthor}**\n\nUptime before restarting: **${client.formatTime(client.uptime as number, 3, {commas: true, longNames: true})}**`).then(()=>exec('pm2 restart Daggerbot'))},650)
}
});
break
case 'statsgraph':
client.statsGraph = -(interaction.options.getInteger('number', true))
interaction.reply(`Successfully set to \`${client.statsGraph}\`\n*Total data points: **${JSON.parse(readFileSync(path.join(__dirname, '../database/MPPlayerData.json'), {encoding: 'utf8'})).length.toLocaleString()}***`);
break
case 'presence':
},
presence: ()=>{
function convertType(Type?: number){
switch (Type) {
case 0: return 'Playing';
@ -117,7 +105,20 @@ export default {
`Name: **${currentActivities[0].name}**`,
`URL: \`${currentActivities[0].url}\``
].join('\n'))
}
},
statsgraph: ()=>{
client.statsGraph = -(interaction.options.getInteger('number', true));
interaction.reply(`Successfully set to \`${client.statsGraph}\`\n*Total data points: **${JSON.parse(readFileSync(path.join(__dirname, '../database/MPPlayerData.json'), {encoding: 'utf8'})).length.toLocaleString()}***`)
},
logs: ()=>{
interaction.deferReply();
(client.channels.resolve(client.config.mainServer.channels.console) as Discord.TextChannel).send({content: `Uploaded the current console dump as of <t:${Math.round(Date.now()/1000)}:R>`, files: [`${process.env.pm2_home}/logs/Daggerbot-out-0.log`, `${process.env.pm2_home}/logs/Daggerbot-error-0.log`]}).then(()=>interaction.editReply('It has been uploaded to dev server.')).catch((e:Error)=>interaction.editReply(`\`${e.message}\``))
},
restart: ()=>{
client.userLevels.forceSave();
interaction.reply(`Uptime before restarting: **${client.formatTime(client.uptime as number, 3, {commas: true, longNames: true})}**`).then(()=>exec('pm2 restart Daggerbot'))
}
} as any)[interaction.options.getSubcommand()]();
},
data: new SlashCommandBuilder()
.setName('dev')

View File

@ -2,33 +2,15 @@ import Discord,{SlashCommandBuilder} from 'discord.js';
import TClient from 'src/client';
export default {
async run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){
switch(interaction.options.getString('question')){
case 'srp':
const embed = new client.embed().setColor(client.config.embedColor).setTitle('When will SRP (Survival Roleplay) return?').setImage('https://cdn.discordapp.com/attachments/1023338018720989305/1059259250242752562/IMG_8964.png');
interaction.reply({embeds: [embed]})
break;
case 'dlskin':
const embed1 = new client.embed().setColor(client.config.embedColor).setTitle('Daggerwin Logistics hex code').setDescription('The main color will be Onyx (`#353839`) with red bumpers.').setImage('https://cdn.discordapp.com/attachments/801965516947324969/806871878736019456/image0.png');
interaction.reply({embeds: [embed1]})
break;
case 'vtcR':
interaction.reply(`You can get the <@&${client.config.mainServer.roles.vtcmember}> role from <#802283932430106624> by reacting the ProBot\'s message with :truck:\n*VTC skin can also be found in <#801975222609641472> as well.*`)
break;
case 'mpR':
interaction.reply(`You can get the <@&${client.config.mainServer.roles.mpplayer}> role from <#802283932430106624> by reacting the ProBot\'s message with :tractor:`)
break;
case 'fsShader':
const embed2 = new client.embed().setColor(client.config.embedColor).setTitle('Clearing your shader cache folder').setDescription('If your game kees crashing shortly after opening your game, then the shaders might be an issue.\nTo resolve this, you can go to `Documents/My Games/FarmingSimulator2022` and delete the folder called `shader_cache`').setImage('https://cdn.discordapp.com/attachments/1015195575693627442/1015195687970943016/unknown.png');
interaction.reply({embeds: [embed2]})
break;
case 'fsLogfile':
const embed3 = new client.embed().setColor(client.config.embedColor).setTitle('Uploading your log file').setDescription('You can find `log.txt` in `Documents/My Games/FarmingSimulator2022` and upload it into <#596989522395398144> along with your issue, so people can assist you further and help you resolve.').setImage('https://cdn.discordapp.com/attachments/1015195575693627442/1015195643528101958/unknown.png');
interaction.reply({embeds: [embed3]})
break;
case 'ytscam':
const embed4 = new client.embed().setColor(client.config.embedColor).setTitle('Scammers in YouTube comments section').setDescription('If you ever see a comment mentioning a giveaway or anything else, **it\'s a scam!**\nYou should report it to YouTube and move on or ignore it.\nP.S: They\'re on every channel and not just Daggerwin.').setImage('https://cdn.discordapp.com/attachments/1015195575693627442/1068078284996345916/image.png');
interaction.reply({embeds: [embed4]})
}
({
srp: ()=>interaction.reply({embeds: [new client.embed().setColor(client.config.embedColor).setTitle('When will SRP (Survival Roleplay) return?').setImage('https://cdn.discordapp.com/attachments/1023338018720989305/1059259250242752562/IMG_8964.png')]}),
dlskin: ()=>interaction.reply({embeds: [new client.embed().setColor(client.config.embedColor).setTitle('Daggerwin Logistics hex code').setDescription('The main color will be Onyx (`#353839`) with red bumpers.').setImage('https://cdn.discordapp.com/attachments/801965516947324969/806871878736019456/image0.png')]}),
vtcR: ()=>interaction.reply(`You can get the <@&${client.config.mainServer.roles.vtcmember}> role from <#802283932430106624> by reacting <@282859044593598464>'s message with :truck:\n*VTC skin can also be found in <#801975222609641472> as well.*`),
mpR: ()=>interaction.reply(`You can get the <@&${client.config.mainServer.roles.mpplayer}> role from <#802283932430106624> by reacting <@282859044593598464>'s message with :tractor:`),
ytscam: ()=>interaction.reply({embeds: [new client.embed().setColor(client.config.embedColor).setTitle('Scammers in YouTube comments section').setDescription('If you ever see a comment mentioning a giveaway or anything else, **it\'s a scam!**\nYou should report it to YouTube and move on or ignore it.\nP.S: They\'re on every channel and not just Daggerwin.').setImage('https://cdn.discordapp.com/attachments/1015195575693627442/1068078284996345916/image.png')]}),
fsShader: ()=>interaction.reply({embeds: [new client.embed().setColor(client.config.embedColor).setTitle('Clearing your shader cache folder').setDescription('If your game kees crashing shortly after opening your game, then the shaders might be an issue.\nTo resolve this, you can go to `Documents/My Games/FarmingSimulator2022` and delete the folder called `shader_cache`').setImage('https://cdn.discordapp.com/attachments/1015195575693627442/1015195687970943016/unknown.png')]}),
fsLogfile: ()=>interaction.reply({embeds: [new client.embed().setColor(client.config.embedColor).setTitle('Uploading your log file').setDescription('You can find `log.txt` in `Documents/My Games/FarmingSimulator2022` and upload it into <#596989522395398144> along with your issue, so people can assist you further and help you resolve.').setImage('https://cdn.discordapp.com/attachments/1015195575693627442/1015195643528101958/unknown.png')]})
} as any)[interaction.options.getString('question', true)]();
},
data: new SlashCommandBuilder()
.setName('faq')

View File

@ -18,7 +18,7 @@ async function MPdata(client:TClient, interaction:Discord.ChatInputCommandIntera
// 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}) // Finally got around to fixing the command when it cannot ping the host.
FSserver = await client.axios.get(completedURL, {timeout: 2588, headers: {'User-Agent': `Daggerbot - mp cmd/axios ${client.axios.VERSION}`}}) // Finally got around to fixing the command when it cannot ping the host.
} catch(err) {
// Blame Nawdic & RedRover92
embed.setTitle('Host is not responding.');
@ -37,9 +37,8 @@ export default {
});
return;
}
const Subb = interaction.options.getSubcommand();
switch (Subb){
case 'status':
({
status: async()=>{
const embed0 = new client.embed();
const FSserver0 = await MPdata(client, interaction, embed0);
if (!FSserver0?.data) return console.log('FSserver0 failed - status');
@ -60,11 +59,66 @@ export default {
console.log(err)
interaction.reply('FSserver0 Placeholder')
};
break;
case 'players':
},
info: async()=>{
const embed2 = new client.embed().setColor(client.config.embedColor)
const FSserver2 = await MPdata(client, interaction, embed2)
if (!FSserver2?.data) return console.log('FSserver2 failed - info')
const DBURL = MPDB.findOne({where: {serverId: interaction.guildId}})
embed2.setDescription([
`**Server name**: \`${FSserver2?.data.server.name.length == 0 ? '\u200b' : FSserver2?.data.server.name}\``,
'**Password:** `mf4700`',
'**Crossplay server**',
`**Map:** ${FSserver2.data.server.mapName.length == 0 ? 'Null Island' : FSserver2.data.server.mapName}`,
`**Mods:** [Click here](${(await DBURL).ip}/mods.html) **|** [Direct Download](${(await DBURL).ip}/all_mods_download?onlyActive=true)`,
'**Filters:** [Click here](https://discord.com/channels/468835415093411861/468835769092669461/926581585938120724)',
'Please see <#543494084363288637> for additional information.'
].join('\n'));
if (FSserver2?.data.server.name.length == 0){
embed2.setFooter({text: 'Server is currently offline.'})
}
interaction.reply({embeds: [embed2]})
},
url: async()=>{
if (!interaction.member.roles.cache.has(client.config.mainServer.roles.mpmanager) && !interaction.member.roles.cache.has(client.config.mainServer.roles.bottech) && !interaction.member.roles.cache.has(client.config.mainServer.roles.admin)) return client.youNeedRole(interaction, 'mpmanager');
MPDB.sync();
const address = interaction.options.getString('address');
if (!address){
try {
const Url = await MPDB.findOne({where:{serverId: 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}`)
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=')
try{
console.log(`MPDB | URL for ${interaction.guild.name} has been updated by ${interaction.member.displayName} (${interaction.member.id})`);
const Url = await MPDB.create({
serverId: interaction.guildId,
ip: newURL[0],
code: newURL[1],
timesUpdated: 0
});
return interaction.reply(`Successfully set the URL to ${Url.ip}`)
} catch(err){
if (err.name == 'SequelizeUniqueConstraintError'){
const AffectedRows = await MPDB.update({ip: newURL[0], code: newURL[1]},{where:{serverId: interaction.guildId}});
await MPDB.increment('timesUpdated',{where:{serverId: interaction.guildId}});
if (AffectedRows) return interaction.reply(`Successfully updated the URL to ${newURL[0]}`)
}else{
console.log(err)
interaction.reply(`\`MPDB\` has caught an error, notify <@&${client.config.mainServer.roles.bottech}>`)
}
}
}
},
players: async()=>{
const embed1 = new client.embed();
const data = JSON.parse(fs.readFileSync(path.join(__dirname, '../database/MPPlayerData.json'), {encoding: 'utf8'})).slice(client.statsGraph)
// handle negative days
data.forEach((change: number, i: number) => {
if (change < 0) data[i] = data[i - 1] || data[i + 1] || 0;
@ -224,65 +278,8 @@ export default {
embed1.addFields({name: `${player.name} ${player.isAdmin ? '| admin' : ''}`, value: `Farming for ${(Math.floor(player.uptime/60))} hr, ${('0' + (player.uptime % 60)).slice(-2)} min`})
})
interaction.reply({embeds: [embed1], files: [Image]})
break;
case 'info':
const embed2 = new client.embed().setColor(client.config.embedColor)
const FSserver2 = await MPdata(client, interaction, embed2)
if (!FSserver2?.data) return console.log('FSserver2 failed - info')
const DBURL = MPDB.findOne({where: {serverId: interaction.guildId}})
embed2.setDescription([
`**Server name**: \`${FSserver2?.data.server.name.length == 0 ? '\u200b' : FSserver2?.data.server.name}\``,
'**Password:** `mf4700`',
'**Crossplay server**',
`**Map:** ${FSserver2.data.server.mapName.length == 0 ? 'Null Island' : FSserver2.data.server.mapName}`,
`**Mods:** [Click here](${(await DBURL).ip}/mods.html) **|** [Direct Download](${(await DBURL).ip}/all_mods_download?onlyActive=true)`,
'**Filters:** [Click here](https://discord.com/channels/468835415093411861/468835769092669461/926581585938120724)',
'Please see <#543494084363288637> for additional information.'
].join('\n'));
if (FSserver2?.data.server.name.length == 0){
embed2.setFooter({text: 'Server is currently offline.'})
}
interaction.reply({embeds: [embed2]})
break;
case 'url':
if (!interaction.member.roles.cache.has(client.config.mainServer.roles.mpmanager) && !interaction.member.roles.cache.has(client.config.mainServer.roles.bottech) && !interaction.member.roles.cache.has(client.config.mainServer.roles.admin)) return client.youNeedRole(interaction, 'mpmanager');
MPDB.sync();
const address = interaction.options.getString('address');
if (!address){
try {
const Url = await MPDB.findOne({where:{serverId: 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}`)
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=')
try{
console.log(`MPDB | URL for ${interaction.guild.name} has been updated by ${interaction.member.displayName} (${interaction.member.id})`);
const Url = await MPDB.create({
serverId: interaction.guildId,
ip: newURL[0],
code: newURL[1],
timesUpdated: 0
});
return interaction.reply(`Successfully set the URL to ${Url.ip}`)
} catch(err){
if (err.name == 'SequelizeUniqueConstraintError'){
const AffectedRows = await MPDB.update({ip: newURL[0], code: newURL[1]},{where:{serverId: interaction.guildId}});
await MPDB.increment('timesUpdated',{where:{serverId: interaction.guildId}});
if (AffectedRows) return interaction.reply(`Successfully updated the URL to ${newURL[0]}`)
}else{
console.log(err)
interaction.reply(`\`MPDB\` has caught an error, notify <@&${client.config.mainServer.roles.bottech}>`)
}
}
}
break;
/* case 'series':
}/*,
series: ()=>{
const embed3 = new client.embed().setColor(client.config.embedColor).setTitle('How to join the Daggerwin MP series')
.setDescription([
'To join the Daggerwin MP series, you first need to:',
@ -292,8 +289,9 @@ export default {
'**4:** If you don\'t receive the role within a day or so, please message an Admin and they will sort it out.',
'**5:** Take a look in <#511657659364147200> to get information on how to join the server.'
].join('\n'));
interaction.reply({embeds: [embed3]}) */
}
interaction.reply({embeds: [embed3]})
}*/
} as any)[interaction.options.getSubcommand()]();
},
data: new SlashCommandBuilder()
.setName('mp')

View File

@ -6,172 +6,164 @@ import fs from 'node:fs';
export default {
async run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){
if (interaction.guildId !== client.config.mainServer.id) return interaction.reply({content: 'This command doesn\'t work in this server.', ephemeral: true});
const subCmd = interaction.options.getSubcommand();
({
view: ()=>{
// fetch user or user interaction sender
const member = interaction.options.getMember("member") ?? interaction.member as Discord.GuildMember;
if (member.user.bot) return interaction.reply('Bots don\'t level up, try viewing non-bots instead.')
const embed = new client.embed().setColor(member.displayColor)
// information about users progress on level roles
const information = client.userLevels._content[member.user.id];
if (subCmd === "leaderboard") {
const messageCountsTotal = Object.values<UserLevels>(client.userLevels._content).reduce((a, b) => a + b.messages, 0);
const timeActive = Math.floor((Date.now() - client.config.LRSstart)/1000/60/60/24);
const dailyMsgsPath = path.join(__dirname, '../database/dailyMsgs.json');
const data = JSON.parse(fs.readFileSync(dailyMsgsPath, {encoding: 'utf8'})).map((x: Array<number>, i: number, a: any) => {
const yesterday = a[i - 1] || [];
return x[1] - (yesterday[1] || x[1]);
}).slice(1).slice(-60);
// handle negative days
data.forEach((change: number, i: number) => {
if (change < 0) data[i] = data[i - 1] || data[i + 1] || 0;
});
const maxValue = Math.max(...data);
const maxValueArr = maxValue.toString().split('');
const first_graph_top = Math.ceil(maxValue * 10 ** (-maxValueArr.length + 1)) * 10 ** (maxValueArr.length - 1);
// console.log({ first_graph_top });
const second_graph_top = Math.ceil(maxValue * 10 ** (-maxValueArr.length + 2)) * 10 ** (maxValueArr.length - 2);
// console.log({ second_graph_top });
const textSize = 32;
const canvas = require('canvas');
const img = canvas.createCanvas(950, 450);
const ctx = img.getContext('2d');
const graphOrigin = [10, 50];
const graphSize = [700, 360];
const nodeWidth = graphSize[0] / (data.length - 1);
ctx.fillStyle = '#36393f';
ctx.fillRect(0, 0, img.width, img.height);
// grey horizontal lines
ctx.lineWidth = 3;
let interval_candidates = [];
for (let i = 4; i < 10; i++) {
const interval = first_graph_top / i;
if (Number.isInteger(interval)) {
let intervalString = interval.toString();
const reference_number = i * Math.max(intervalString.split('').filter(x => x === '0').length / intervalString.length, 0.3) * (['1', '2', '4', '5', '6', '8'].includes(intervalString[0]) ? 1.5 : 0.67)
interval_candidates.push([interval, i, reference_number]);
const pronounBool = (you: string, they: string) => { // takes 2 words and chooses which to use based on if user did this command on themself
if (interaction.user.id === member.user.id) return you || true;
else return they || false;
};
if (!information) {
return interaction.reply(`${pronounBool('You', 'They')} currently don't have a level, send some messages to level up.`)
}
}
// console.log({ interval_candidates });
const chosen_interval = interval_candidates.sort((a, b) => b[2] - a[2])[0];
// console.log({ chosen_interval });
let previousY: Array<number> = [];
ctx.strokeStyle = '#202225';
for (let i = 0; i <= chosen_interval[1]; i++) {
const y = graphOrigin[1] + graphSize[1] - (i * (chosen_interval[0] / second_graph_top) * graphSize[1]);
if (y < graphOrigin[1]) continue;
const even = ((i + 1) % 2) === 0;
if (even) ctx.strokeStyle = '#2c2f33';
const index = Object.entries<UserLevels>(client.userLevels._content).sort((a, b) => b[1].messages - a[1].messages).map(x => x[0]).indexOf(member.id) + 1;
const memberDifference = information.messages - client.userLevels.algorithm(information.level);
const levelDifference = client.userLevels.algorithm(information.level+1) - client.userLevels.algorithm(information.level);
embed.setThumbnail(member.user.avatarURL({ extension: 'png', size: 256}) || member.user.defaultAvatarURL)
embed.setAuthor({name: `Ranking for ${member.user.tag}`})
embed.setTitle(`Level: **${information.level}**\nRank: **${index ? '#' + index : 'last'}**\nProgress: **${information.messages - client.userLevels.algorithm(information.level)}/${client.userLevels.algorithm(information.level+1) - client.userLevels.algorithm(information.level)} (${(memberDifference/levelDifference*100).toFixed(2)}%)**\nTotal: **${information.messages}**`);
interaction.reply({embeds: [embed]})
},
leaderboard: ()=>{
const messageCountsTotal = Object.values<UserLevels>(client.userLevels._content).reduce((a, b) => a + b.messages, 0);
const timeActive = Math.floor((Date.now() - client.config.LRSstart)/1000/60/60/24);
const dailyMsgsPath = path.join(__dirname, '../database/dailyMsgs.json');
const data = JSON.parse(fs.readFileSync(dailyMsgsPath, {encoding: 'utf8'})).map((x: Array<number>, i: number, a: any) => {
const yesterday = a[i - 1] || [];
return x[1] - (yesterday[1] || x[1]);
}).slice(1).slice(-60);
// handle negative days
data.forEach((change: number, i: number) => {
if (change < 0) data[i] = data[i - 1] || data[i + 1] || 0;
});
const maxValue = Math.max(...data);
const maxValueArr = maxValue.toString().split('');
const first_graph_top = Math.ceil(maxValue * 10 ** (-maxValueArr.length + 1)) * 10 ** (maxValueArr.length - 1);
const second_graph_top = Math.ceil(maxValue * 10 ** (-maxValueArr.length + 2)) * 10 ** (maxValueArr.length - 2);
const textSize = 32;
const canvas = require('canvas');
const img = canvas.createCanvas(950, 450);
const ctx = img.getContext('2d');
const graphOrigin = [10, 50];
const graphSize = [700, 360];
const nodeWidth = graphSize[0] / (data.length - 1);
ctx.fillStyle = '#36393f';
ctx.fillRect(0, 0, img.width, img.height);
// grey horizontal lines
ctx.lineWidth = 3;
let interval_candidates = [];
for (let i = 4; i < 10; i++) {
const interval = first_graph_top / i;
if (Number.isInteger(interval)) {
let intervalString = interval.toString();
const reference_number = i * Math.max(intervalString.split('').filter(x => x === '0').length / intervalString.length, 0.3) * (['1', '2', '4', '5', '6', '8'].includes(intervalString[0]) ? 1.5 : 0.67)
interval_candidates.push([interval, i, reference_number]);
}
}
const chosen_interval = interval_candidates.sort((a, b) => b[2] - a[2])[0];
let previousY: Array<number> = [];
ctx.strokeStyle = '#202225';
for (let i = 0; i <= chosen_interval[1]; i++) {
const y = graphOrigin[1] + graphSize[1] - (i * (chosen_interval[0] / second_graph_top) * graphSize[1]);
if (y < graphOrigin[1]) continue;
const even = ((i + 1) % 2) === 0;
if (even) ctx.strokeStyle = '#2c2f33';
ctx.beginPath();
ctx.lineTo(graphOrigin[0], y);
ctx.lineTo(graphOrigin[0] + graphSize[0], y);
ctx.stroke();
ctx.closePath();
if (even) ctx.strokeStyle = '#202225';
previousY = [y, i * chosen_interval[0]];
}
// 30d mark
ctx.setLineDash([8, 16]);
ctx.beginPath();
ctx.lineTo(graphOrigin[0], y);
ctx.lineTo(graphOrigin[0] + graphSize[0], y);
const lastMonthStart = graphOrigin[0] + (nodeWidth * (data.length - 30));
ctx.lineTo(lastMonthStart, graphOrigin[1]);
ctx.lineTo(lastMonthStart, graphOrigin[1] + graphSize[1]);
ctx.stroke();
ctx.closePath();
if (even) ctx.strokeStyle = '#202225';
previousY = [y, i * chosen_interval[0]];
ctx.setLineDash([]);
// draw points
ctx.strokeStyle = client.config.embedColor;
ctx.fillStyle = client.config.embedColor;
ctx.lineWidth = 3;
function getYCoordinate(value: number) {
return ((1 - (value / second_graph_top)) * graphSize[1]) + graphOrigin[1];
}
let lastCoords: Array<number> = [];
data.forEach((val: number, i: number) => {
ctx.beginPath();
if (lastCoords) ctx.moveTo(...lastCoords);
if (val < 0) val = 0;
const x = i * nodeWidth + graphOrigin[0];
const y = getYCoordinate(val);
ctx.lineTo(x, y);
lastCoords = [x, y];
ctx.stroke();
ctx.closePath();
// ball
ctx.beginPath();
ctx.arc(x, y, ctx.lineWidth * 1.2, 0, 2 * Math.PI)
ctx.closePath();
ctx.fill();
});
// draw text
ctx.font = '400 ' + textSize + 'px sans-serif';
ctx.fillStyle = 'white';
// highest value
const maxx = graphOrigin[0] + graphSize[0] + textSize;
const maxy = previousY[0] + (textSize / 3);
ctx.fillText(previousY[1].toLocaleString('en-US'), maxx, maxy);
// lowest value
const lowx = graphOrigin[0] + graphSize[0] + textSize;
const lowy = graphOrigin[1] + graphSize[1] + (textSize / 3);
ctx.fillText('0 msgs/day', lowx, lowy);
// 30d
ctx.fillText('30d ago', lastMonthStart, graphOrigin[1] - (textSize / 3));
// time ->
const tx = graphOrigin[0] + (textSize / 2);
const ty = graphOrigin[1] + graphSize[1] + (textSize);
ctx.fillText('time ->', tx, ty);
const yeahok = new client.attachmentBuilder(img.toBuffer(), {name: 'dailymsgs.png'})
const embed = new client.embed().setTitle('Ranking leaderboard')
.setDescription(`Level System was created **${timeActive}** days ago. Since then, a total of **${messageCountsTotal.toLocaleString('en-US')}** messages have been sent in this server.\nGraph updates daily @ <t:${Math.round((client.config.LRSstart+3600000)/1000)}:t>`)
.addFields({name: 'Top users by messages sent:', value: Object.entries<UserLevels>(client.userLevels._content).sort((a, b) => b[1].messages - a[1].messages).slice(0, 10).map((x, i) => `\`${i + 1}.\` <@${x[0]}>: ${x[1].messages.toLocaleString('en-US')}`).join('\n')})
.setImage('attachment://dailymsgs.png').setColor(client.config.embedColor)
interaction.reply({embeds: [embed], files: [yeahok]})
}
// 30d mark
ctx.setLineDash([8, 16]);
ctx.beginPath();
const lastMonthStart = graphOrigin[0] + (nodeWidth * (data.length - 30));
ctx.lineTo(lastMonthStart, graphOrigin[1]);
ctx.lineTo(lastMonthStart, graphOrigin[1] + graphSize[1]);
ctx.stroke();
ctx.closePath();
ctx.setLineDash([]);
// draw points
ctx.strokeStyle = client.config.embedColor;
ctx.fillStyle = client.config.embedColor;
ctx.lineWidth = 3;
function getYCoordinate(value: number) {
return ((1 - (value / second_graph_top)) * graphSize[1]) + graphOrigin[1];
}
let lastCoords: Array<number> = [];
data.forEach((val: number, i: number) => {
ctx.beginPath();
if (lastCoords) ctx.moveTo(...lastCoords);
if (val < 0) val = 0;
const x = i * nodeWidth + graphOrigin[0];
const y = getYCoordinate(val);
ctx.lineTo(x, y);
lastCoords = [x, y];
ctx.stroke();
ctx.closePath();
// ball
ctx.beginPath();
ctx.arc(x, y, ctx.lineWidth * 1.2, 0, 2 * Math.PI)
ctx.closePath();
ctx.fill();
});
// draw text
ctx.font = '400 ' + textSize + 'px sans-serif';
ctx.fillStyle = 'white';
// highest value
const maxx = graphOrigin[0] + graphSize[0] + textSize;
const maxy = previousY[0] + (textSize / 3);
ctx.fillText(previousY[1].toLocaleString('en-US'), maxx, maxy);
// lowest value
const lowx = graphOrigin[0] + graphSize[0] + textSize;
const lowy = graphOrigin[1] + graphSize[1] + (textSize / 3);
ctx.fillText('0 msgs/day', lowx, lowy);
// 30d
ctx.fillText('30d ago', lastMonthStart, graphOrigin[1] - (textSize / 3));
// time ->
const tx = graphOrigin[0] + (textSize / 2);
const ty = graphOrigin[1] + graphSize[1] + (textSize);
ctx.fillText('time ->', tx, ty);
const yeahok = new client.attachmentBuilder(img.toBuffer(), {name: 'dailymsgs.png'})
const embed = new client.embed().setTitle('Ranking leaderboard')
.setDescription(`Level System was created **${timeActive}** days ago. Since then, a total of **${messageCountsTotal.toLocaleString('en-US')}** messages have been sent in this server.\nGraph updates daily @ <t:${Math.round((client.config.LRSstart+3600000)/1000)}:t>`)
.addFields({name: 'Top users by messages sent:', value: Object.entries<UserLevels>(client.userLevels._content).sort((a, b) => b[1].messages - a[1].messages).slice(0, 10).map((x, i) => `\`${i + 1}.\` <@${x[0]}>: ${x[1].messages.toLocaleString('en-US')}`).join('\n')})
.setImage('attachment://dailymsgs.png').setColor(client.config.embedColor)
interaction.reply({embeds: [embed], files: [yeahok]});
return;
} else if (subCmd === "view") {
// fetch user or user interaction sender
const member = interaction.options.getMember("member") ?? interaction.member as Discord.GuildMember;
if (member.user.bot) return interaction.reply('Bots don\'t level up, try viewing non-bots instead.')
const embed = new client.embed().setColor(member.displayColor)
// information about users progress on level roles
const information = client.userLevels._content[member.user.id];
const pronounBool = (you: string, they: string) => { // takes 2 words and chooses which to use based on if user did this command on themself
if (interaction.user.id === member.user.id) return you || true;
else return they || false;
};
if (!information) {
return interaction.reply(`${pronounBool('You', 'They')} currently don't have a level, send some messages to level up.`)
}
const index = Object.entries<UserLevels>(client.userLevels._content).sort((a, b) => b[1].messages - a[1].messages).map(x => x[0]).indexOf(member.id) + 1;
const memberDifference = information.messages - client.userLevels.algorithm(information.level);
const levelDifference = client.userLevels.algorithm(information.level+1) - client.userLevels.algorithm(information.level);
embed.setThumbnail(member.user.avatarURL({ extension: 'png', size: 256}) || member.user.defaultAvatarURL)
embed.setAuthor({name: `Ranking for ${member.user.tag}`})
embed.setTitle(`Level: **${information.level}**\nRank: **${index ? '#' + index : 'last'}**\nProgress: **${information.messages - client.userLevels.algorithm(information.level)}/${client.userLevels.algorithm(information.level+1) - client.userLevels.algorithm(information.level)} (${(memberDifference/levelDifference*100).toFixed(2)}%)**\nTotal: **${information.messages}**`);
interaction.reply({embeds: [embed]});
}
} as any)[interaction.options.getSubcommand()]();
},
data: new SlashCommandBuilder()
.setName('rank')

View File

@ -1,22 +1,21 @@
import Discord,{SlashCommandBuilder} from 'discord.js';
import TClient from 'src/client';
function convert(status:string){
switch (status){
case 'offline':
return '⚫'
case 'idle':
return '🟡'
case 'dnd':
return '🔴'
case 'online':
return '🟢'
function convert(status?:Discord.ClientPresenceStatus){
if (status){
return {
idle: '🟡',
dnd: '🔴',
online: '🟢'
}[status];
} else {
return '⚫'
}
}
export default {
async run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){
const member = interaction.options.getMember('member') as Discord.GuildMember;
const member = interaction.options.getMember('member');
if (member == null){
const user = interaction.options.getUser('member') as Discord.User;
const embed = new client.embed()
@ -30,22 +29,27 @@ export default {
} else {
await member.user.fetch();
const embedArray = [];
const presence = member.presence.clientStatus as Discord.ClientPresenceStatusData;
let title = 'Member';
if (member.user.bot) {
title = 'Bot'
} else if (member.user.id == interaction.guild.ownerId) {
title = ':crown: Server Owner'
};
const embed0 = new client.embed()
.setColor(member.displayColor || client.config.embedColor)
.setURL(`https://discord.com/users/${member.user.id}`)
.setThumbnail(member.user.avatarURL({size:2048}) || member.user.defaultAvatarURL)
.setImage(member.user.bannerURL({size:1024}) as string)
.setTitle(`${member.user.bot ? 'Bot' : 'Member'} Info: ${member.user.tag}`)
.setDescription(`<@${member.user.id}>\n\`${member.user.id}\`${member.user.id === interaction.guild.ownerId ? '\n__**Server Owner**__ 👑' : ''}`)
.setTitle(`${title} Info: ${member.user.tag}`)
.setDescription(`<@${member.user.id}>\n\`${member.user.id}\``)
.addFields(
{name: '🔹 Account Creation Date', value: `<t:${Math.round(member.user.createdTimestamp/1000)}>\n<t:${Math.round(member.user.createdTimestamp/1000)}:R>`},
{name: '🔹 Server Join Date', value: `<t:${Math.round((member.joinedTimestamp as number)/1000)}>\n<t:${Math.round((member.joinedTimestamp as number)/1000)}:R>`},
{name: `🔹 Roles: ${member.roles.cache.size - 1}`, value: member.roles.cache.size > 1 ? member.roles.cache.filter(x=>x.id !== interaction.guild.roles.everyone.id).sort((a,b)=>b.position - a.position).map(x=>x).join(member.roles.cache.size > 4 ? ' ' : '\n').slice(0,1024) : 'No roles'}
)
if (member.premiumSinceTimestamp !== null){
embed0.addFields({name: '🔹 Server Boosting since', value: `<t:${Math.round(member.premiumSinceTimestamp/1000)}>\n<t:${Math.round(member.premiumSinceTimestamp/1000)}:R>`, inline: true})
}
if (member.presence){embed0.addFields({name: `🔹 Status: ${member.presence.status}`, value: `${member.presence.status === 'offline' ? '⚫' : `Desktop: ${(member.presence.clientStatus as Discord.ClientPresenceStatusData).desktop ? convert((member.presence.clientStatus as Discord.ClientPresenceStatusData).desktop as string) : convert('offline')}\nWeb: ${(member.presence.clientStatus as Discord.ClientPresenceStatusData).web ? convert((member.presence.clientStatus as Discord.ClientPresenceStatusData).web as string) : convert('offline')}\nMobile: ${(member.presence.clientStatus as Discord.ClientPresenceStatusData).mobile ? convert((member.presence.clientStatus as Discord.ClientPresenceStatusData).mobile as string) : convert('offline')}`}`, inline: true})}
if (member.premiumSinceTimestamp !== null) embed0.addFields({name: '🔹 Server Boosting since', value: `<t:${Math.round(member.premiumSinceTimestamp/1000)}>\n<t:${Math.round(member.premiumSinceTimestamp/1000)}:R>`, inline: true})
if (member.presence) embed0.addFields({name: `🔹 Status: ${member.presence.status}`, value: `${member.presence.status === 'offline' ? '⚫' : `Desktop: ${convert(presence.desktop)}\nWeb: ${convert(presence.web)}\nMobile: ${convert(presence.mobile)}`}`, inline: true})
embedArray.push(embed0)
interaction.reply({embeds: embedArray})
}