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

enough coding for now, gonna get milk™️

This commit is contained in:
toast-ts 2022-11-18 04:58:19 +11:00
parent 49af49423b
commit 386ee4f54e
25 changed files with 794 additions and 131 deletions

5
.gitignore vendored
View File

@ -5,4 +5,7 @@ package-lock.json
# TypeScript stuff
dist/
# Bot stuff
src/database/MPDB.dat
src/database/MPDB.dat
src/commands/disabled
src/commands/roleinfo.ts
src/commands/rank.ts

1
botStartup.sh Normal file
View File

@ -0,0 +1 @@
npx ts-node src/index.ts

View File

@ -32,8 +32,9 @@
"discord.js": "14.6.0",
"moment": "2.29.4",
"ms": "2.1.3",
"sequelize": "7.0.0-alpha.9",
"sequelize": "6.25.6",
"sqlite3": "5.1.2",
"systeminformation": "5.12.15",
"xml-js": "1.6.11"
},
"devDependencies": {

View File

@ -2,6 +2,7 @@ import Discord, { Client, GatewayIntentBits, Partials } from 'discord.js';
import fs from 'node:fs';
import { Database } from './database';
import timeNames from './timeNames';
import { Punishment, formatTimeOpt, createTableOpt, punOpt } from './typings/interfaces';
export class TClient extends Client {
invites: Map<any, any>;
commands: Discord.Collection<string, any>;
@ -30,14 +31,14 @@ export class TClient extends Client {
GatewayIntentBits.Guilds, GatewayIntentBits.GuildMembers,
GatewayIntentBits.GuildBans, GatewayIntentBits.GuildInvites,
GatewayIntentBits.GuildPresences, GatewayIntentBits.GuildMessageReactions,
GatewayIntentBits.DirectMessages, GatewayIntentBits.MessageContent
GatewayIntentBits.DirectMessages, GatewayIntentBits.MessageContent, GatewayIntentBits.GuildMessages
],
partials: [
Partials.Channel,
Partials.Reaction,
Partials.Message
],
allowedMentions: { users: [], roles: [] } // idk if it would work but requires testing...
allowedMentions: { users: [], roles: [] }
})
this.invites = new Map();
this.commands = new Discord.Collection();
@ -77,7 +78,7 @@ export class TClient extends Client {
this.registry.push(command.default.data.toJSON())
}
}
formatPunishmentType(punishment: Punishment, client: TClient, cancels: Punishment){
formatPunishmentType(punishment: Punishment, client: TClient, cancels?: Punishment){
if (punishment.type == 'removeOtherPunishment'){
cancels ||= this.punishments._content.find((x: Punishment)=>x.id === punishment.cancels)
return cancels.type[0].toUpperCase()+cancels.type.slice(1)+' Removed';
@ -86,13 +87,12 @@ export class TClient extends Client {
formatTime(integer: number, accuracy = 1, options?: formatTimeOpt){
let achievedAccuracy = 0;
let text:any = '';
const { longNames, commas } = options
for (const timeName of timeNames){
if (achievedAccuracy < accuracy){
const fullTimelengths = Math.floor(integer/timeName.length);
if (fullTimelengths == 0) continue;
achievedAccuracy++;
text += fullTimelengths + (longNames ? (' '+timeName.name+(fullTimelengths === 1 ? '' : 's')) : timeName.name.slice(0, timeName.name === 'month' ? 2 : 1)) + (commas ? ', ' : ' ');
text += fullTimelengths + (options?.longNames ? (' '+timeName.name+(fullTimelengths === 1 ? '' : 's')) : timeName.name.slice(0, timeName.name === 'month' ? 2 : 1)) + (options?.commas ? ', ' : ' ');
integer -= fullTimelengths*timeName.length;
} else {
break;
@ -182,8 +182,8 @@ export class TClient extends Client {
async punish(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>, type: string){
let result: any;
if (!client.isStaff(interaction.member as Discord.GuildMember)) return this.youNeedRole(interaction, 'dcmod')
if (type !== ('warn' || 'mute') && (interaction.member as Discord.GuildMember).roles.cache.has(client.config.mainServer.roles.idk)) return this.youNeedRole(interaction, 'dcmod');
const time = this.ms(interaction.options.getString('time'));
//if (type !== ('warn' || 'mute') && (interaction.member as Discord.GuildMember).roles.cache.has(client.config.mainServer.roles.idk)) return this.youNeedRole(interaction, 'dcmod');
const time = interaction.options.getString('time') as string;
const reason = interaction.options.getString('reason') ?? 'Reason unspecified';
if (type == 'ban'){
const user = interaction.options.getUser('member') as Discord.User;
@ -208,7 +208,18 @@ export class TClient extends Client {
}
async YTLoop(YTChannelID: string, YTChannelName: string, DCChannelID: string){
const Data = this.xjs.xml2js((await this.axios.get(`https://www.youtube.com/feeds/videos.xml?channel_id=${YTChannelID}`, {timeout: 5000})), {compact: true, spaces: 2}).catch(()=>{return null});
let Data:any;
let error;
try {
await this.axios.get(`https://www.youtube.com/feeds/videos.xml?channel_id=${YTChannelID}`, {timeout: 5000}).then((xml:any)=>{
Data = this.xjs.xml2js(xml.data, {compact: true, spaces: 2});
})
} catch(err){
error = true;
console.log(`\x1b[36m[${this.moment().format('DD/MM/YY HH:mm:ss')}]`, `\x1b[31m${YTChannelName} YT fail`)
}
if (!Data) return;
if (this.YTCache[YTChannelID] == undefined){
this.YTCache[YTChannelID] = Data.feed.entry[0]['yt:videoId']._text;
@ -251,7 +262,7 @@ class punishments extends Database {
}
switch (type) {
case 'ban':
const banData: Punishment={type, id: this.createId(), member: member.id, moderator, time: now};
const banData:Punishment={type, id: this.createId(), member: member.id, moderator, time: now};
const dm1: Discord.Message = await member.send(`You've been banned from ${interaction.guild.name} ${timeInMillis ? `for ${this.client.formatTime(timeInMillis, 4, {longNames: true, commas: true})} (${timeInMillis}ms)` : 'forever'} for reason \`${reason || 'Reason unspecified'}\` (Case #${banData.id})`).catch(()=>{return interaction.channel.send('Failed to DM user.')})
const banResult = await interaction.guild.bans.create(member.id, {reason: `${reason || 'Reason unspecified'} | Case #${banData.id}`}).catch((err:Error)=>err.message);
if (typeof banResult === 'string'){
@ -272,16 +283,84 @@ class punishments extends Database {
}
case 'softban':
const guild = member.guild;
const softbanData: Punishment={type, id: this.createId(), member: member.user.id, moderator, time: now};
const softbanData:Punishment={type, id: this.createId(), member: member.user.id, moderator, time: now};
const dm2 = Discord.Message = await member.send(`You've been softbanned from ${member.guild.name} ${timeInMillis ? `for ${this.client.formatTime(timeInMillis, 4, {longNames: true, commas: true})} (${timeInMillis}ms)` : 'forever'} for reason \`${reason || 'Reason unspecified'}\` (Case #${softbanData.id})`).catch(()=>{return interaction.channel.send('Failed to DM user.')})
const softbanResult = await member.ban({deleteMessageDays: 3, reason: `${reason || 'Reason unspecified'} | Case #${softbanData.id}`}).catch((err:Error)=>err.message);
if (typeof softbanResult === 'string') {
dm2.delete();
return `Softban was unsuccessful: ${softbanResult}`;
} else {
const unbanResult = guild.members.unban(softbanData.member, `${reason || 'Reason unspecified'} | Case #${softbanData.id}`).catch((err:Error)=>err.message);
if (typeof unbanResult === 'string'){
return `Softban (unban) was unsuccessful: ${softbanResult}`
} else {
if (reason) softbanData.reason = reason;
this.client.makeModlogEntry(softbanData, this.client);
this.addData(softbanData).forceSave();
return new this.client.embed().setColor(this.client.config.embedColor).setTitle(`Case #${softbanData.id}: Softban`).setDescription(`${member.user.tag}\n<@${member.user.tag}>\n(\`${member.user.id}\`)`).addFields(
{name: 'Reason', value: `\`${reason || 'Reason unspecified'}\``}
)
}
}
case 'kick':
const kickData:Punishment={type, id: this.createId(), member: member.user.id, moderator, time: now};
const dm3: Discord.Message = await member.send(`You've been kicked from ${member.guild.name} for reason \`${reason || 'Reason unspecified'}\` (Case #${kickData.id})`).catch(()=>{interaction.channel.send(`Failed to DM <@${member.user.id}>.`); return null});
const kickResult = await member.kick(`${reason || 'Reason unspecified'} | Case #${kickData.id}`).catch((err:Error)=>err.message)
if (typeof kickResult === 'string'){
if (dm3) dm3.delete();
return `Kick was unsuccessful: ${kickResult}`
} else {
if (reason) kickData.reason = reason;
this.client.makeModlogEntry(kickData, this.client);
this.addData(kickData).forceSave();
return new this.client.embed().setColor(this.client.config.embedColor).setTitle(`Case #${kickData.id}: Kick`).setDescription(`${member.user.tag}\n<@${member.user.id}>\n(\`${member.user.id}\`)`).addFields(
{name: 'Reason', value: `\`${reason || 'Reason unspecified'}\``}
)
}
case 'warn':
const warnData:Punishment={type, id: this.createId(), member: member.user.id, moderator, time: now};
const warnResult: Discord.Message = await member.send(`You've been warned in ${member.guild.name} for reason \`${reason || 'Reason unspecified'}\` (Case #${warnData.id})`).catch(()=>{interaction.channel.send(`Failed to DM <@${member.user.id}>`); return null;})
if (typeof warnResult === 'string'){
return `Warn was unsuccessful: ${warnResult}`
} else {
if (reason) warnData.reason = reason;
this.client.makeModlogEntry(warnData, this.client);
this.addData(warnData).forceSave();
const embedw = new this.client.embed().setColor(this.client.config.embedColor).setTitle(`Case #${warnData.id}: Warn`).setDescription(`${member.user.tag}\n<@${member.user.id}>\n(\`${member.user.id}\`)`).addFields(
{name: 'Reason', value: `\`${reason || 'Reason unspecified'}\``}
)
if (moderator !== '795443537356521502') {return embedw}
}
case 'mute':
const muteData:Punishment={type, id: this.createId(), member: member.user.id, moderator, time: now};
let muteResult;
if (this.client.isStaff(member)) return 'Staff cannot be muted.'
const dm4: Discord.Message = await member.send(`You've been muted in ${member.guild.name} ${timeInMillis ? `for ${this.client.formatTime(timeInMillis, 4, {longNames: true, commas: true})} (${timeInMillis}ms)` : 'forever'} for reason \`${reason || 'Reason unspecified'}\` (Case #${muteData.id})`).catch(()=>{interaction.channel.send('Failed to DM user.'); return null});
if (timeInMillis) {
muteResult = await member.timeout(timeInMillis, `${reason || 'Reason unspecified'} | Case #${muteData.id}`).catch((err:Error)=>err.message);
} else {
muteResult = await member.timeout(2419200000, `${reason || 'Reason unspecified'} | Case #${muteData.id}`).catch((err:Error)=>err.message);
}
if (typeof muteResult === 'string'){
if (dm4) dm4.delete();
return `Mute was unsuccessful: ${muteResult}`;
} else {
if (timeInMillis) {
muteData.endTime = now + timeInMillis;
muteData.duration = timeInMillis;
}
if (reason) muteData.reason = reason;
this.client.makeModlogEntry(muteData, this.client);
this.addData(muteData).forceSave();
const embedm = new this.client.embed().setColor(this.client.config.embedColor).setTitle(`Case #${muteData.id}: Mute`).setDescription(`${member.user.tag}\n<@${member.user.id}>\n(\`${member.user.id}\`)`).addFields(
{name: 'Reason', value: `\`${reason || 'Reason unspecified'}\``},
{name: 'Duration',
value: `${this.client.formatTime(timeInMillis, 4, {
longNames: true,
commas: true
})} (${timeInMillis}ms)`})
if (moderator !== '795443537356521502') {return embedm};
}
}
}
async removePunishment(caseId:number, moderator:any, reason:string):Promise<any>{}

32
src/commands/bonk.ts Normal file
View File

@ -0,0 +1,32 @@
import Discord,{SlashCommandBuilder} from 'discord.js';
import { TClient } from 'src/client';
export default {
async run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){
if (!client.isStaff(interaction.member) && interaction.channelId == '468835415093411863') return interaction.reply('This command is restricted to staff only in this channel due to high usage.')
const member = interaction.options.getUser('member');
const reason = interaction.options.getString('reason');
const adminPerm = interaction.member.permissions.has('Administrator')
if (!member) {
return interaction.reply('You can\'t bonk the ghost.')
} else {
//if (member && adminPerm) return interaction.reply('You cannot bonk an admin!')
if (member) {
const embed = new client.embed().setColor(client.config.embedColor)
.setDescription(`> <@${member.id}> has been bonked!\n${reason?.length == null ? '' : `> Reason: ${reason}`}`)
.setImage('https://media.tenor.com/7tRddlNUNNcAAAAd/hammer-on-head-minions.gif')
.setFooter({text: `Bonk count for ${member.tag}: ${await client.bonkCount.getUser(member.id).toLocaleString('en-US')}`})
interaction.reply({embeds: [embed]})
client.bonkCount._incrementUser(member.id).forceSave();
}
}
},
data: new SlashCommandBuilder()
.setName('bonk')
.setDescription('Bonk a member')
.addUserOption((opt)=>opt
.setName('member')
.setDescription('Which member to bonk?'))
.addStringOption((opt)=>opt
.setName('reason')
.setDescription('Reason for the bonk'))
}

View File

@ -0,0 +1,20 @@
import Discord,{SlashCommandBuilder} from 'discord.js';
import { TClient } from 'src/client';
export default {
async run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){
const embed = new client.embed().setColor(client.config.embedColor).setTitle('Daggerbot contributors').setDescription([
'Toast <@190407856527376384>',
'TÆMBØ <@615761944154210305>',
'Buzz <@593696856165449749>',
'Monster <@215497515934416896>',
'RainbowDave <@141304507249197057>',
'Hitchhiker <@506022868157595648>',
'RedRover92 <@633345781780185099>',
'Nawdic <@178941218510602240>'
].join('\n'))
interaction.reply({embeds: [embed]})
},
data: new SlashCommandBuilder()
.setName('contributors')
.setDescription('List of people who helped and worked on the bot.')
}

58
src/commands/fsurl.ts Normal file
View File

@ -0,0 +1,58 @@
import Discord,{SlashCommandBuilder} from 'discord.js';
import { TClient } from 'src/client';
import MPDB from '../models/MPServer';
export default {
async run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){
if (interaction.guildId !== client.config.mainServer.id) return interaction.reply('This command doesn\'t work in this server.');
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 newServerId = interaction.guildId
const address = interaction.options.getString('address')
if (!address) {
try {
const Url = await MPDB.findOne({where: {serverId: newServerId}})
if (Url.ip && Url.code){return interaction.reply(`${Url.get('ip')}` + '/feed/dedicated-server-stats.json?code=' + `${Url.get('code')}`)}
} catch(err) {
if (err.name == 'SequelizeDatabaseError'){
console.log('MPDB | File doesn\'t exist in database folder, generating one now.')
interaction.reply('`MPDB.dat` is being createdm run the command again.')
} else {
console.log(`MPDB | Error: ${err}`)
interaction.reply('Database error:\nTry inserting an URL first.')
}
}
} else {
const verifyURL = address.match(/feed/)
if (!verifyURL) return interaction.reply('Invalid URL, try again.')
const convertURL = address
const newURL = convertURL.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: newServerId,
ip: newURL[0],
code: newURL[1]
});
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: newServerId}});
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}>`)
}
}
}
},
data: new SlashCommandBuilder()
.setName('url')
.setDescription('Update the URL for FSMP functions')
.addStringOption((opt)=>opt
.setName('address')
.setDescription('Insert a \'dedicated-server-stats\' url')
.setRequired(false))
}

262
src/commands/mp.ts Normal file
View File

@ -0,0 +1,262 @@
import Discord,{EmbedBuilder, SlashCommandBuilder} from 'discord.js';
import { TClient } from 'src/client';
import MPDB from '../models/MPServer';
async function MPdata(client:TClient, interaction:Discord.ChatInputCommandInteraction, embed: EmbedBuilder) {
let FSserver;
MPDB.sync();
const newServerId = interaction.guildId;
const ServerURL = await MPDB.findOne({where: { serverId: newServerId }});
const DBURL = ServerURL.ip
const DBCode = ServerURL.code
const verifyURL = DBURL.match(/http/)
const completedURL = DBURL + '/feed/dedicated-server-stats.json?code=' + DBCode
if (!verifyURL) return interaction.reply(`No gameserver found, please contact <@&${client.config.mainServer.roles.mpmanager}> to update it.`)
// Fetch dss
try {
FSserver = await client.axios.get(completedURL, {timeout: 2800}) // 2800 seems doable with database latency added to it.
} catch(err) {
// Blame Nawdic & RedRover92
embed.setTitle('Host is not responding.');
embed.setColor(client.config.embedColorRed);
interaction.reply({embeds: [embed]});
console.log('dag mp fail to fetch, host is not responding.');
return;
}
return FSserver
}
export default {
async run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){
if (interaction.channelId == '468835769092669461' && !client.isStaff(interaction.member) && ['status', 'players'].includes(interaction.options.getSubcommand())) {
interaction.reply(`Please use <#739084625862852715> for \`/mp status/players\` commands to prevent clutter in this channel.`).then((msg)=>{
setTimeout(()=>{interaction.deleteReply()}, 500)
});
return;
}
const Subb = interaction.options.getSubcommand();
switch (Subb){
case 'status':
const embed0 = new client.embed();
const FSserver0 = await MPdata(client, interaction, embed0);
if (FSserver0.data.server.name.length > 1) {
embed0.setTitle('Status/Details').setColor(client.config.embedColor).addFields(
{name: 'Server name', value: `${FSserver0?.data.server.name.length == 0 ? '\u200b' : `\`${FSserver0?.data.server.name}\``}`, inline: true},
{name: 'Players', value: `${FSserver0.data.slots.used} out of ${FSserver0.data.slots.capacity}`, inline: true},
{name: 'Current map', value: `${FSserver0?.data.server.mapName.length == 0 ? '\u200b' : FSserver0.data.server.mapName}`, inline: true},
{name: 'Version', value: `${FSserver0?.data.server.version.length == 0 ? '\u200b' : FSserver0.data.server.version}`, inline: true},
{name: 'In-game Time', value: `${('0' + Math.floor((FSserver0.data.server.dayTime/3600/1000))).slice(-2)}:${('0' + Math.floor((FSserver0.data.server.dayTime/60/1000)%60)).slice(-2)}`, inline: true}
)
}
interaction.reply({embeds: [embed0]})
break;
case 'players':
const embed1 = new client.embed();
const data = require('../database/MPPlayerData.json').slice(-60)
// handle negative days
data.forEach((change: number, i: number) => {
if (change < 0) data[i] = data[i - 1] || data[i + 1] || 0;
});
const first_graph_top = 16;
const second_graph_top = 16;
const textSize = 40;
const canvas = require('canvas');
const img = canvas.createCanvas(1500, 750);
const ctx = img.getContext('2d');
const graphOrigin = [15, 65];
const graphSize = [1300, 630];
const nodeWidth = graphSize[0] / (data.length - 1);
ctx.fillStyle = '#36393f';
ctx.fillRect(0, 0, img.width, img.height);
// grey horizontal lines
ctx.lineWidth = 5;
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];
const 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.push(y, i * chosen_interval[0]);
}
// 30m mark
ctx.setLineDash([8, 16]);
ctx.beginPath();
const lastMonthStart = graphOrigin[0] + (nodeWidth * (data.length - 60));
ctx.lineTo(lastMonthStart, graphOrigin[1]);
ctx.lineTo(lastMonthStart, graphOrigin[1] + graphSize[1]);
ctx.stroke();
ctx.closePath();
ctx.setLineDash([]);
// draw points
ctx.lineWidth = 5;
function getYCoordinate(value: number) {
return ((1 - (value / second_graph_top)) * graphSize[1]) + graphOrigin[1];
}
function colorAtPlayercount(playercount: number) {
if (playercount === first_graph_top) {
return client.config.embedColorRed;
} else if (playercount > 9) {
return client.config.embedColorYellow;
} else {return client.config.embedColorGreen;}
}
let lastCoords: Array<number> = [];
data.forEach((curPC: number /* current player count */, i: number) => {
if (curPC < 0) curPC = 0;
const x = i * nodeWidth + graphOrigin[0];
const y = getYCoordinate(curPC);
const nexPC /* next player count */ = data[i + 1];
const prvPC /* previous player count */ = data[i - 1];
const curColor = colorAtPlayercount(curPC); // color now
const prvColor = colorAtPlayercount(prvPC); // color at last point
if (curColor !== prvColor && !isNaN(prvPC) && lastCoords.length > 0) { // gradient should be used when the color between now and last point is not the same
// gradient from now to last point
const grd = ctx.createLinearGradient(...lastCoords, x, y);
grd.addColorStop(0, colorAtPlayercount(prvPC)); // prev color at the beginning
grd.addColorStop(1, colorAtPlayercount(curPC)); // cur color at the end
// special case: playercount rises or falls rapidly accross all colors (eg. straight from red to green)
if (curColor !== client.config.embedColorYellow && prvColor !== client.config.embedColorYellow) {
const yellowY = getYCoordinate(10); // y coordinate at which line should be yellow
const stop = (yellowY - lastCoords[1]) / (y - lastCoords[1]); // between 0 and 1, where is yellowY between y and nextPointCoords[1] ?
grd.addColorStop(stop, client.config.embedColorYellow); // add a yellow stop to the gradient
}
ctx.strokeStyle = grd;
} else {
ctx.strokeStyle = colorAtPlayercount(curPC);
}
ctx.beginPath();
if (lastCoords.length > 0) ctx.moveTo(...lastCoords);
// if the line being drawn is horizontal, make it go until it has to go down
if (y === lastCoords[1]) {
let newX = x;
for (let j = i + 1; j <= data.length; j++) {
if (data[j] === curPC) newX += nodeWidth; else break;
}
ctx.lineTo(newX, y);
} else {
ctx.lineTo(x, y);
}
lastCoords = [x, y];
ctx.stroke();
ctx.closePath();
if (curPC === prvPC && curPC === nexPC) {
return; // no ball because no vertical difference to next or prev point
} else {
// ball
ctx.fillStyle = colorAtPlayercount(curPC);
ctx.beginPath();
ctx.arc(x, y, ctx.lineWidth * 1.3, 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 / 2;
const maxy = previousY[0] + (textSize / 3);
ctx.fillText(previousY[1].toLocaleString('en-US'), maxx, maxy);
// lowest value
const lowx = graphOrigin[0] + graphSize[0] + textSize / 2;
const lowy = graphOrigin[1] + graphSize[1] + (textSize / 3);
ctx.fillText('0 players', lowx, lowy);
// 30m
ctx.fillText('30 mins ago', lastMonthStart, graphOrigin[1] - (textSize / 2));
// time ->
const tx = graphOrigin[0] + (textSize / 2);
const ty = graphOrigin[1] + graphSize[1] + (textSize);
ctx.fillText('time ->', tx, ty);
const Image = new client.attachmentBuilder(img.toBuffer(),{name: 'FSStats.png'})
embed1.setImage('attachment://FSStats.png')
const FSserver1 = await MPdata(client, interaction, embed1)
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`})
})
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)
const DBURL = MPDB.findOne({where: {serverId: interaction.guildId}})
embed2.setDescription([
`**Server name**: ${FSserver2?.data.server.name.length == 0 ? 'Unknown Server' : `\`${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)'
].join('\n'));
interaction.reply({embeds: [embed2]})
break;
case '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:',
'**1:** Note that only PC players can join the MP series due to the mods that are used.',
'**2:** Become a YouTube Member by pressing the `Join` button on [Daggerwin\'s YouTube page](https://www.youtube.com/c/Daggerwin) next to the `Subscribe` button.',
'**3:** Link your YouTube account to your Discord account via Settings>Connections>Add connection. Be sure that you link the same YouTube account you used to become a channel member.',
'**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]})
}
},
data: new SlashCommandBuilder()
.setName('mp')
.setDescription('Display MP status and other things')
.addSubcommand((opt)=>opt
.setName('status')
.setDescription('Check server status and details'))
.addSubcommand((opt)=>opt
.setName('players')
.setDescription('Check who\'s playing on the server'))
.addSubcommand((opt)=>opt
.setName('info')
.setDescription('Provides you with server information such as filters and so on'))
.addSubcommand((opt)=>opt
.setName('series')
.setDescription('Step-by-step on joining Daggerwin\'s MP series'))
}

20
src/commands/mute.ts Normal file
View File

@ -0,0 +1,20 @@
import Discord,{SlashCommandBuilder} from 'discord.js';
import { TClient } from 'src/client';
export default {
async run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){
client.punish(client, interaction, 'mute');
},
data: new SlashCommandBuilder()
.setName('mute')
.setDescription('Mute a member')
.addUserOption((opt)=>opt
.setName('member')
.setDescription('Which member to mute?')
.setRequired(true))
.addStringOption((opt)=>opt
.setName('time')
.setDescription('Mute duration'))
.addStringOption((opt)=>opt
.setName('reason')
.setDescription('Reason for the mute'))
}

View File

@ -4,7 +4,7 @@ export default {
async run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){
const msg = await interaction.reply({content: 'Pinging...', fetchReply: true})
const time = msg.createdTimestamp - interaction.createdTimestamp;
msg.edit(`Websocket: \`${client.ws.ping}\`ms\nBot: \`${time}\``)
msg.edit(`Websocket: \`${client.ws.ping}\`ms\nBot: \`${time}\`ms`)
},
data: new SlashCommandBuilder()
.setName('ping')

11
src/commands/restart.ts Normal file
View File

@ -0,0 +1,11 @@
import Discord,{SlashCommandBuilder} from 'discord.js';
import { TClient } from 'src/client';
export default {
async run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){
if (!client.config.eval.whitelist.includes(interaction.user.id)) return client.youNeedRole(interaction, 'bottech');
interaction.reply('Restarting...').then(()=>require('node:child_process').exec('pm2 restart Daggerbot'))
},
data: new SlashCommandBuilder()
.setName('restart')
.setDescription('Restart the bot for technical reasons')
}

View File

@ -0,0 +1,85 @@
import Discord,{SlashCommandBuilder, version} from 'discord.js';
import { TClient } from 'src/client';
import si from 'systeminformation';
import os from 'node:os';
import { versionMajorMinor } from 'typescript';
import { VERSION } from 'ts-node';
export default {
async run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){
switch (interaction.options.getSubcommand()) {
case 'commands':
const columns = ['Command name', 'Count'];
const includedCommands = client.commands.filter(x=>x.uses).sort((a,b)=>b.uses - a.uses);
if (includedCommands.size == 0) return interaction.reply(`No commands have been used yet.\nUptime: ${client.formatTime(client.uptime as number, 2, {longNames: true, commas: true})}`);
const nameLength = Math.max(...includedCommands.map(x=>x.default.data.name.length), columns[0].length) + 2;
const amountLength = Math.max(...includedCommands.map(x=>x.uses.toLocaleString().length), columns[1].length) + 1;
const rows = [`${columns[0] + ' '.repeat(nameLength - columns[0].length)}|${' '.repeat(amountLength - columns[1].length) + columns[1]}\n`, '-'.repeat(nameLength) + '-'.repeat(amountLength) + '\n'];
includedCommands.forEach(command=>{
const name = command.default.data.name;
const count = command.uses.toString();
rows.push(`${name + ' '.repeat(nameLength - name.length)}${' '.repeat(amountLength - count.length) + count}\n`);
});
const embed = new client.embed().setColor(client.config.embedColor).setTitle('Statistics: Command Usage')
.setDescription([
'List of commands that have been used in this session, ordered by amount of use. Table contains command name and amount of uses.',
`Total amount of commands used in this session: ${client.commands.filter(x=>x.uses).map(x=>x.uses).reduce((a,b)=>a+b, 0)}`
].join('\n'))
if (rows.join('').length > 1024){
let fieldValue = '';
rows.forEach(row=>{
if (fieldValue.length + row.length > 1024){
embed.addFields({name: '\u200b', value: `\`\`\`\n${fieldValue}\`\`\``});
fieldValue = row;
} else {
fieldValue += row;
}
});
embed.addFields({name: '\u200b', value: `\`\`\`\n${fieldValue}\`\`\``});
} else {
embed.addFields({name: '\u200b', value: `\`\`\`\n${rows.join('')}\`\`\``})
};
interaction.reply({embeds: [embed]})
break;
case 'host':
// Bytes conversion
function formatBytes(bytes, decimals = 2) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const dm = decimals < 0 ? 0 : decimals;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
}
await interaction.deferReply();
const cpu = await si.cpu();
const ram = await si.mem();
const osInfo = await si.osInfo();
const currentLoad = await si.currentLoad();
const embed1 = new client.embed().setColor(client.config.embedColor).setTitle('Statistics: Host Info').setDescription([
`> __Dependencies__`,
`**TypeScript:** ${versionMajorMinor}`,
`**TS-Node:** ${VERSION}`,
`**NodeJS:** ${process.version}`,
`**DiscordJS:** ${version}`,
`> __Host__`,
`**Operating System:** ${osInfo.distro + ' ' + osInfo.release}`,
`**CPU:** ${cpu.manufacturer, cpu.brand}`,
`**Memory:** ${formatBytes(ram.used)}/${formatBytes(ram.total)}`,
`**NodeJS:** ${formatBytes(process.memoryUsage().heapUsed)}/${formatBytes(process.memoryUsage().heapTotal)}`,
`**Load Usage:**\nUser: ${currentLoad.currentLoadUser.toFixed(1)}%\nSystem: ${currentLoad.currentLoadSystem.toFixed(1)}%`,
`**Uptime:**\nHost: ${client.formatTime((os.uptime()*1000), 2, {longNames: true, commas: true})}\nBot: ${client.formatTime(client.uptime as number, 2, {commas: true, longNames: true})}`
].join('\n'))
.setFooter({text: `Load time: ${Date.now() - interaction.createdTimestamp}ms`});
interaction.editReply({embeds: [embed1]});
}
},
data: new SlashCommandBuilder()
.setName('statistics')
.setDescription('See a list of commands ordered by their usage or bot stats')
.addSubcommand((opt)=>opt
.setName('commands')
.setDescription('View command usage stats'))
.addSubcommand((opt)=>opt
.setName('host')
.setDescription('View host stats'))
}

View File

@ -12,7 +12,7 @@ export default {
} else if (stdout.includes('Already up to date')){
msg.edit(`Pull aborted:\nUp to date with the repository`)
} else {
setTimeout(()=>{msg.edit('Restarting...').then(()=>eval(process.exit(-1)))},1000)
setTimeout(()=>{msg.edit('Restarting...').then(()=>require('node:child_process').exec('pm2 restart Daggerbot'))},1000)
}
}
)

61
src/commands/whois.ts Normal file
View File

@ -0,0 +1,61 @@
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 '🟢'
}
}
export default {
async run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){
const member = interaction.options.getMember('member') as Discord.GuildMember;
if (member == null){
const user = interaction.options.getUser('member') as Discord.User;
const embed = new client.embed()
.setColor(client.config.embedColor)
.setURL(`https://discord.com/users/${user.id}`)
.setThumbnail(user.avatarURL({size:2048}) || user.defaultAvatarURL)
.setTitle(`${user.bot ? 'Bot': 'User'} Info: ${user.tag}`)
.setDescription(`<@${user.id}>\n\`${user.id}\``)
.addFields({name: '🔹 Account Creation Date', value: `<t:${Math.round(user.createdTimestamp/1000)}>\n<t:${Math.round(user.createdTimestamp/1000)}:R>`})
interaction.reply({embeds: [embed]})
} else {
await member.user.fetch();
const embedArray = [];
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**__ 👑' : ''}`)
.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'}
)
console.log(member.guild.banner)
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})}
embedArray.push(embed0)
interaction.reply({embeds: embedArray})
}
},
data: new SlashCommandBuilder()
.setName('whois')
.setDescription('View your own or someone else\'s information')
.addUserOption((opt)=>opt
.setName('member')
.setDescription('Member or user to view their information')
.setRequired(true))
}

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
["fuck","fck","fů","fuk","fúck","fùck","fûck","fück","fūck","fůck","fűck","fùçk","fûćk","fucking","fųck","shit","shite","sht","shìt","shít","shît","shït","shīt","shįt","shıt","shlt","whore","pelotudo","boludo","nigger","nigga","nigs","niggas@","cunt","cnut","bitch","dick","pussy","asshole","b1tch","b!tch","blowjob","cock","c0ck","retard","fag","faggot","tits","boobs","dick","sex","porn","bjob","stfu","","­","͏","͏","؜","","","","","","","","stfu","ass","kkk","<@1011334031478100099>","<@468835415093411861>","asf","af","wtf","piss","pissed","pissing"]
["fuck","fck","fů","fuk","fúck","fùck","fûck","fück","fūck","fůck","fűck","fùçk","fûćk","fucking","fųck","shit","shite","sht","shìt","shít","shît","shït","shīt","shįt","shıt","shlt","whore","pelotudo","boludo","nigger","nigga","nigs","niggas@","cunt","cnut","bitch","dick","pussy","asshole","b1tch","b!tch","blowjob","cock","c0ck","retard","fag","faggot","tits","boobs","dick","sex","porn","bjob","stfu","","­","͏","͏","؜","","","","","","","","stfu","ass","kkk","<@1011334031478100099>","<@468835415093411861>","asf","af","wtf","piss","pissed"]

View File

@ -1 +1 @@
[[0,674965],[1,675885],[2,676639],[3,677245],[4,677609],[5,678188],[6,678916],[7,679465],[8,679938],[9,680540],[10,681614],[11,682079],[12,682780],[13,683187],[14,683547],[15,683900],[16,684592],[17,685466],[18,686078],[19,686481],[20,676748],[21,676968],[22,677427],[23,677592],[24,677894],[25,678116],[26,676785],[27,677570],[28,678491],[29,679137],[30,679818],[31,680094],[32,680417],[33,680783],[34,681563],[35,682070],[36,682670],[37,683504],[38,684078],[39,684383],[40,684692],[41,685448],[42,685664],[43,685994],[44,686366],[45,687118],[46,687626],[47,688008],[48,688754],[49,688942],[50,689107],[51,689472],[52,690143],[53,690644],[54,691124],[55,692196],[56,692624],[57,692906],[58,693456],[59,693952],[60,694586],[61,695070],[62,696163],[63,696564],[64,697315],[65,698548],[66,699138],[67,699558],[68,700307],[69,701063],[70,701394],[71,701868],[72,702453],[73,702917],[76,705187],[77,705243],[78,705488],[79,705961],[80,706585],[81,707467],[82,708212],[83,709024],[84,709773],[85,710256]]
[[0,674965],[1,675885],[2,676639],[3,677245],[4,677609],[5,678188],[6,678916],[7,679465],[8,679938],[9,680540],[10,681614],[11,682079],[12,682780],[13,683187],[14,683547],[15,683900],[16,684592],[17,685466],[18,686078],[19,686481],[20,676748],[21,676968],[22,677427],[23,677592],[24,677894],[25,678116],[26,676785],[27,677570],[28,678491],[29,679137],[30,679818],[31,680094],[32,680417],[33,680783],[34,681563],[35,682070],[36,682670],[37,683504],[38,684078],[39,684383],[40,684692],[41,685448],[42,685664],[43,685994],[44,686366],[45,687118],[46,687626],[47,688008],[48,688754],[49,688942],[50,689107],[51,689472],[52,690143],[53,690644],[54,691124],[55,692196],[56,692624],[57,692906],[58,693456],[59,693952],[60,694586],[61,695070],[62,696163],[63,696564],[64,697315],[65,698548],[66,699138],[67,699558],[68,700307],[69,701063],[70,701394],[71,701868],[72,702453],[73,702917],[76,705187],[77,705243],[78,705488],[79,705961],[80,706585],[81,707467],[82,708212],[83,709024],[84,709773],[85,710256],[86,710980]]

View File

@ -94,5 +94,13 @@
"moderator": "532662366354276352",
"time": 1668331244780,
"reason": "innapropiate profile picture"
},
{
"type": "ban",
"id": 13,
"member": "985447227755495425",
"moderator": "141304507249197057",
"time": 1668526989338,
"reason": "steam scammer"
}
]

View File

@ -1,54 +1,54 @@
{
"190407856527376384": {
"messages": 53012,
"messages": 53029,
"level": 59
},
"593696856165449749": {
"messages": 51421,
"messages": 51456,
"level": 58
},
"141304507249197057": {
"messages": 67626,
"messages": 67631,
"level": 67
},
"533707949831487488": {
"messages": 56992,
"messages": 57038,
"level": 61
},
"532662366354276352": {
"messages": 33701,
"messages": 33775,
"level": 47
},
"824043915539513406": {
"messages": 18442,
"messages": 18452,
"level": 35
},
"178941218510602240": {
"messages": 6375,
"messages": 6394,
"level": 20
},
"215497515934416896": {
"messages": 33124,
"messages": 33129,
"level": 46
},
"301350210926280704": {
"messages": 14317,
"messages": 14334,
"level": 30
},
"695323013813633076": {
"messages": 14076,
"messages": 14090,
"level": 30
},
"389237487094071337": {
"messages": 12240,
"messages": 12254,
"level": 28
},
"716355511552966737": {
"messages": 9138,
"messages": 9146,
"level": 24
},
"633345781780185099": {
"messages": 29365,
"messages": 29379,
"level": 44
},
"711527768185372742": {
@ -64,31 +64,31 @@
"level": 18
},
"458688902102908928": {
"messages": 6209,
"messages": 6237,
"level": 20
},
"475037861725339649": {
"messages": 10194,
"messages": 10201,
"level": 26
},
"392699530912727041": {
"messages": 4937,
"messages": 4944,
"level": 18
},
"468837263577579524": {
"messages": 7677,
"messages": 7695,
"level": 22
},
"734703851558535188": {
"messages": 20203,
"messages": 20211,
"level": 36
},
"488683638310043677": {
"messages": 15457,
"messages": 15477,
"level": 32
},
"606595407769894995": {
"messages": 23240,
"messages": 23251,
"level": 39
},
"322835877027905547": {
@ -96,7 +96,7 @@
"level": 25
},
"485793265568841728": {
"messages": 37883,
"messages": 37885,
"level": 50
},
"837979120142778388": {
@ -112,7 +112,7 @@
"level": 18
},
"690090143008555064": {
"messages": 9974,
"messages": 9978,
"level": 25
},
"849633082440941628": {
@ -120,15 +120,15 @@
"level": 0
},
"687720203773149238": {
"messages": 572,
"level": 0
"messages": 573,
"level": 6
},
"452576735494406175": {
"messages": 1679,
"messages": 1684,
"level": 10
},
"763055599654666291": {
"messages": 971,
"messages": 972,
"level": 8
},
"623176215800446976": {
@ -148,11 +148,11 @@
"level": 0
},
"169891949464125441": {
"messages": 521,
"messages": 538,
"level": 5
},
"718453763932946432": {
"messages": 13548,
"messages": 13549,
"level": 30
},
"472809522226790420": {
@ -160,7 +160,7 @@
"level": 13
},
"763803832542035978": {
"messages": 683,
"messages": 685,
"level": 6
},
"931816463113814066": {
@ -172,7 +172,7 @@
"level": 0
},
"771892617599516674": {
"messages": 626,
"messages": 630,
"level": 6
},
"468437000232501269": {
@ -188,7 +188,7 @@
"level": 0
},
"309373272594579456": {
"messages": 3585,
"messages": 3588,
"level": 15
},
"399625244588900362": {
@ -200,7 +200,7 @@
"level": 0
},
"615761944154210305": {
"messages": 3063,
"messages": 3070,
"level": 14
},
"397101726047666197": {
@ -228,7 +228,7 @@
"level": 2
},
"645342896312156181": {
"messages": 684,
"messages": 693,
"level": 6
},
"488505753133645826": {
@ -240,7 +240,7 @@
"level": 2
},
"848489550065827850": {
"messages": 42,
"messages": 44,
"level": 1
},
"862138850423472128": {
@ -248,7 +248,7 @@
"level": 1
},
"700053257996992573": {
"messages": 75,
"messages": 76,
"level": 2
},
"949404588673482872": {
@ -280,7 +280,7 @@
"level": 0
},
"509374532109336576": {
"messages": 29,
"messages": 31,
"level": 1
},
"464887328138199042": {
@ -344,7 +344,7 @@
"level": 1
},
"132183685658050561": {
"messages": 8,
"messages": 9,
"level": 0
},
"549295707304099846": {
@ -400,8 +400,8 @@
"level": 0
},
"903147621961588757": {
"messages": 14,
"level": 0
"messages": 15,
"level": 1
},
"386627658773168137": {
"messages": 2,
@ -416,15 +416,15 @@
"level": 0
},
"774337023804833825": {
"messages": 81,
"level": 0
"messages": 83,
"level": 2
},
"700434438890323990": {
"messages": 9,
"level": 0
},
"281518331427553280": {
"messages": 28,
"messages": 29,
"level": 1
},
"708758234407895050": {
@ -528,7 +528,7 @@
"level": 0
},
"818595993121062974": {
"messages": 46,
"messages": 48,
"level": 1
},
"273755695680192513": {
@ -540,7 +540,7 @@
"level": 0
},
"869718328313278555": {
"messages": 97,
"messages": 98,
"level": 2
},
"772197160372404234": {
@ -632,7 +632,7 @@
"level": 0
},
"280115935057281024": {
"messages": 1,
"messages": 2,
"level": 0
},
"595727217271635969": {
@ -652,7 +652,7 @@
"level": 0
},
"188304766923833344": {
"messages": 21,
"messages": 22,
"level": 1
},
"749311773819142326": {
@ -668,8 +668,8 @@
"level": 1
},
"673950857238413362": {
"messages": 12,
"level": 0
"messages": 16,
"level": 1
},
"434344693824749568": {
"messages": 3,
@ -764,7 +764,7 @@
"level": 0
},
"552473047144071168": {
"messages": 20,
"messages": 21,
"level": 1
},
"587377817893994538": {
@ -820,7 +820,7 @@
"level": 0
},
"513009978315898891": {
"messages": 20,
"messages": 23,
"level": 1
},
"667815332047486978": {
@ -1052,7 +1052,7 @@
"level": 0
},
"781289786143932499": {
"messages": 107,
"messages": 111,
"level": 2
},
"348617165135544321": {
@ -1232,8 +1232,8 @@
"level": 0
},
"444415772001959936": {
"messages": 14,
"level": 0
"messages": 16,
"level": 1
},
"629585796290314250": {
"messages": 103,
@ -1312,7 +1312,7 @@
"level": 0
},
"486352184707907585": {
"messages": 4,
"messages": 5,
"level": 0
},
"309170189164085249": {
@ -1340,8 +1340,8 @@
"level": 0
},
"98464148379148288": {
"messages": 1436,
"level": 9
"messages": 1504,
"level": 10
},
"1025723411680460840": {
"messages": 1,
@ -1372,7 +1372,7 @@
"level": 0
},
"786733440003211285": {
"messages": 15,
"messages": 17,
"level": 1
},
"853043920505012255": {
@ -1472,7 +1472,7 @@
"level": 0
},
"889624632724963329": {
"messages": 38,
"messages": 51,
"level": 1
},
"687692546314600530": {
@ -1656,7 +1656,7 @@
"level": 0
},
"937750032344571934": {
"messages": 102,
"messages": 103,
"level": 2
},
"873149038709571594": {
@ -1684,7 +1684,7 @@
"level": 0
},
"633339908827643974": {
"messages": 12,
"messages": 13,
"level": 0
},
"174267277187874816": {
@ -1724,8 +1724,8 @@
"level": 0
},
"796040852400635914": {
"messages": 367,
"level": 4
"messages": 396,
"level": 5
},
"1011307308325818438": {
"messages": 23,
@ -1740,7 +1740,7 @@
"level": 0
},
"673289306424475659": {
"messages": 122,
"messages": 129,
"level": 2
},
"907163452043305000": {
@ -1824,7 +1824,7 @@
"level": 0
},
"335637071878422529": {
"messages": 125,
"messages": 127,
"level": 2
},
"646684489573203968": {
@ -1856,7 +1856,7 @@
"level": 0
},
"1031950921233600662": {
"messages": 15,
"messages": 17,
"level": 1
},
"907951346769092618": {
@ -1924,7 +1924,7 @@
"level": 0
},
"813866707365265419": {
"messages": 109,
"messages": 114,
"level": 2
},
"726188513518813275": {
@ -1944,7 +1944,7 @@
"level": 0
},
"715615331938467962": {
"messages": 8,
"messages": 9,
"level": 0
},
"1033047374597214298": {
@ -1968,7 +1968,7 @@
"level": 0
},
"1030526730462572558": {
"messages": 191,
"messages": 192,
"level": 3
},
"530533266206359552": {
@ -2092,7 +2092,7 @@
"level": 0
},
"123080080946757632": {
"messages": 37,
"messages": 39,
"level": 1
},
"1001530115148226711": {
@ -2120,7 +2120,7 @@
"level": 0
},
"969867332304400404": {
"messages": 6,
"messages": 7,
"level": 0
},
"881867367418826812": {
@ -2228,7 +2228,7 @@
"level": 0
},
"591972887812898816": {
"messages": 1,
"messages": 2,
"level": 0
},
"718100655851438090": {
@ -2320,7 +2320,7 @@
"level": 0
},
"1029465066174677132": {
"messages": 10,
"messages": 11,
"level": 0
},
"387345064927428611": {
@ -2340,7 +2340,7 @@
"level": 0
},
"938332923042598933": {
"messages": 1,
"messages": 2,
"level": 0
},
"719181129390751755": {
@ -2352,7 +2352,7 @@
"level": 0
},
"972513020972519484": {
"messages": 87,
"messages": 94,
"level": 2
},
"953310806538330163": {
@ -2376,7 +2376,7 @@
"level": 0
},
"703628676310368257": {
"messages": 4,
"messages": 6,
"level": 0
},
"444715401159639042": {
@ -2488,7 +2488,7 @@
"level": 0
},
"284482432684785664": {
"messages": 2,
"messages": 3,
"level": 0
},
"727948378067173407": {
@ -2500,7 +2500,7 @@
"level": 0
},
"490183428990304286": {
"messages": 75,
"messages": 77,
"level": 2
},
"787352638811013151": {
@ -2520,7 +2520,7 @@
"level": 0
},
"534500956688351242": {
"messages": 4,
"messages": 8,
"level": 0
},
"989466115803590686": {
@ -2544,7 +2544,7 @@
"level": 0
},
"697953686487564348": {
"messages": 110,
"messages": 123,
"level": 2
},
"664233182941413427": {
@ -2592,7 +2592,7 @@
"level": 0
},
"340587045250531358": {
"messages": 84,
"messages": 86,
"level": 2
},
"911709434554777660": {
@ -2680,7 +2680,7 @@
"level": 0
},
"999736341220839464": {
"messages": 7,
"messages": 9,
"level": 0
},
"901565970974392331": {
@ -2688,7 +2688,7 @@
"level": 0
},
"388211913621897216": {
"messages": 21,
"messages": 22,
"level": 1
},
"1039241529912475729": {
@ -2700,12 +2700,12 @@
"level": 0
},
"995622955897864272": {
"messages": 70,
"messages": 92,
"level": 2
},
"153323923633733632": {
"messages": 8,
"level": 0
"messages": 17,
"level": 1
},
"190028480786726913": {
"messages": 2,
@ -2716,7 +2716,7 @@
"level": 0
},
"590595536537518091": {
"messages": 2,
"messages": 4,
"level": 0
},
"576383133763764225": {
@ -2728,7 +2728,7 @@
"level": 0
},
"328602696040841216": {
"messages": 7,
"messages": 10,
"level": 0
},
"222861120329744387": {
@ -2736,11 +2736,11 @@
"level": 0
},
"927957676120473671": {
"messages": 1,
"messages": 2,
"level": 0
},
"846431793715871749": {
"messages": 1,
"messages": 3,
"level": 0
},
"838471706871988234": {
@ -2748,11 +2748,31 @@
"level": 0
},
"259798326705127435": {
"messages": 1,
"messages": 2,
"level": 0
},
"910647475570901054": {
"messages": 2,
"level": 0
},
"1037133851190890589": {
"messages": 2,
"level": 0
},
"945263081095852042": {
"messages": 5,
"level": 0
},
"521087871776718869": {
"messages": 4,
"level": 0
},
"299940980680032279": {
"messages": 3,
"level": 0
},
"248226483967885312": {
"messages": 2,
"level": 0
}
}

View File

@ -26,7 +26,7 @@ export default {
const usedInvite = newInvites.find((inv:any)=>oldInvites.get(inv.code)?.uses < inv.uses);
newInvites.forEach((inv:any)=>client.invites.set(inv.code,{uses: inv.uses, creator: inv.inviter.id}));
const embed1 = new client.embed().setColor(client.config.embedColorGreen).setTimestamp().setThumbnail(member.user.displayAvatarURL({size: 2048})).setTitle(`Member Joined: ${member.user.tag}`).setDescription(`<@${member.user.id}>\n\`${member.user.id}\``).addFields(
const embed1 = new client.embed().setColor(client.config.embedColorGreen).setTimestamp().setThumbnail(member.user.displayAvatarURL({size: 2048})).setTitle(`Member Joined: ${member.user.tag}`).setDescription(`<@${member.user.id}>\n\`${member.user.id}\``).setFooter({text: `Total members: ${index}${suffix}`}).addFields(
{name: '🔹 Account Creation Date', value: `<t:${Math.round(member.user.createdTimestamp/1000)}>\n<t:${Math.round(member.user.createdTimestamp/1000)}:R>`},
{name: '🔹 Invite Data:', value: usedInvite ? `Invite: \`${usedInvite.code}\`\nCreated by: **${usedInvite.inviter?.tag}**` : 'I couldn\'t find out how they joined!'}
);

View File

@ -3,7 +3,7 @@ import { TClient } from '../client';
export default {
name: 'messageCreate',
execute: async(client:TClient, message:Discord.Message)=>{
if (!client.config.botSwitches.commands && !client.config.eval.whitelist.includes(message.author.id)) return
if (!client.config.botSwitches.commands && !client.config.eval.whitelist.includes(message.author.id)) return
if (message.author.bot) return;
if (message.channel.type === ChannelType.DM) return;
const msgarr = message.content.toLowerCase().split(' ');
@ -73,15 +73,15 @@ export default {
}
// Autoresponse:tm:
if (!client.config.botSwitches.autores && !automodded) {
if (client.config.botSwitches.autores && !automodded) {
if (message.mentions.members.has('309373272594579456') && !client.isStaff(message.member) && message.type != 19){
message.reply('Please don\'t tag Daggerwin, read rule 14 in <#468846117405196289>')
}
if (message.mentions.members.has('215497515934416896') && !client.isStaff(message.member) && message.type != 19){
message.reply('Please don\'t tag Monster unless it\'s important!')
}
if (message.content.toLowerCase().startsWith(`${client.config.prefix}players`) || message.content.toLowerCase().startsWith(`${client.config.prefix}status`)){
message.reply('Commands for the MP server have been moved to `*mp players` and `*mp status`.')
if (message.content.toLowerCase().startsWith(`*mp players`) || message.content.toLowerCase().startsWith(`*mp status`)){
message.reply('Prefix-based MP commands has been moved to `/mp players` and `/mp status`')
}
if (message.content.toLowerCase().includes('whats the password') || message.content.toLowerCase().includes('what\'s the password') || message.content.toLowerCase().includes('password pls')){
message.reply('Password and other details can be found in <#543494084363288637>')

View File

@ -12,7 +12,7 @@ export default {
const msgarr = newMsg.content.toLowerCase().split(' ');
if (client.bannedWords._content.some((word:string)=>msgarr.includes(word)) && (!client.isStaff(newMsg.member))) newMsg.delete();
if (newMsg.content === oldMsg.content) return;
const embed = new client.embed().setColor(client.config.embedColor).setTimestamp().setAuthor({name: `Author: ${oldMsg.author.tag} (${oldMsg.author.id})`, iconURL: `${oldMsg.author.displayAvatarURL()}`}).setTitle('Message edited').setDescription(`<@${oldMsg.author.id}>\nOld content:\n\`\`\`\n${oldMsg.content}\n\`\`\`\nNew content:\n\`\`\`\nChannel: <#${oldMsg.channelId}>`);
const embed = new client.embed().setColor(client.config.embedColor).setTimestamp().setAuthor({name: `Author: ${oldMsg.author.tag} (${oldMsg.author.id})`, iconURL: `${oldMsg.author.displayAvatarURL()}`}).setTitle('Message edited').setDescription(`<@${oldMsg.author.id}>\nOld content:\n\`\`\`\n${oldMsg.content}\n\`\`\`\nNew content:\n\`\`\`\n${newMsg.content}\`\`\`\nChannel: <#${oldMsg.channelId}>`);
(client.channels.resolve(client.config.mainServer.channels.logs) as Discord.TextChannel).send({embeds: [embed], components: [new ActionRowBuilder<ButtonBuilder>().addComponents(new ButtonBuilder().setStyle(5).setURL(`${oldMsg.url}`).setLabel('Jump to message'))]});
}
}

View File

@ -1,14 +1,20 @@
interface punOpt {
time?: string,
reason?: string,
interaction?: any
}
import Discord from 'discord.js';
import { TClient } from './client';
const client = new TClient;
client.init();
import fs from 'node:fs';
import MPDB from './models/MPServer';
import { Punishment } from './typings/interfaces';
client.on('ready', async()=>{
client.guilds.cache.forEach(async(e: { members: { fetch: () => any; }; })=>{await e.members.fetch()});
setInterval(async()=>{
client.user.setPresence({activities: [{ name: 'TypeScript is pog', type: 0 }], status: 'online'});
client.user.setPresence({activities: [{ name: 'Slash commands!', type: 0 }], status: 'online'});
// Playing: 0, Streaming (Requires YT/Twitch URL to work): 1, Listening to: 2, Watching: 3, Competing in: 5
}, 60000);
if (client.config.botSwitches.registerCommands) (client.guilds.cache.get(client.config.mainServer.id) as Discord.Guild).commands.set(client.registry).catch((e)=>{console.log(`Couldn't register slash commands: ${e}`)})
@ -22,7 +28,7 @@ client.on('ready', async()=>{
}, 500000);
console.log(`${client.user.tag} has logged into Discord API and now ready for operation`);
console.log(client.config.botSwitches);
(client.channels.resolve(client.config.mainServer.channels.bot_status) as Discord.TextChannel).send(`${client.user.username} is active\n\`\`\`json\n${Object.entries(client.config.botSwitches).map((hi)=>`${hi[0]}: ${hi[1]}`).join('\n')}\`\`\``);
//(client.channels.resolve(client.config.mainServer.channels.bot_status) as Discord.TextChannel).send(`${client.user.username} is active\n\`\`\`json\n${Object.entries(client.config.botSwitches).map((hi)=>`${hi[0]}: ${hi[1]}`).join('\n')}\`\`\``);
// Event handler
const eventFiles = fs.readdirSync('src/events').filter(file=>file.endsWith('.ts'));
@ -35,21 +41,21 @@ client.on('ready', async()=>{
// Handle errors
process.on('unhandledRejection', async(error: Error)=>{
console.log(error);
(client.channels.resolve(client.config.mainServer.channels.errors) as Discord.TextChannel).send({embeds: [new client.embed().setColor('#420420').setTitle('Error caught!').setDescription(`**Error:** \`${error.message}\`\n\n**Stack:** \`${`${error.stack}`.slice(0, 2500)}\``)]})
//(client.channels.resolve(client.config.mainServer.channels.errors) as Discord.TextChannel).send({embeds: [new client.embed().setColor('#420420').setTitle('Error caught!').setDescription(`**Error:** \`${error.message}\`\n\n**Stack:** \`${`${error.stack}`.slice(0, 2500)}\``)]})
});
process.on('uncaughtException', async(error: Error)=>{
console.log(error);
(client.channels.resolve(client.config.mainServer.channels.errors) as Discord.TextChannel).send({embeds: [new client.embed().setColor('#420420').setTitle('Error caught!').setDescription(`**Error:** \`${error.message}\`\n\n**Stack:** \`${`${error.stack}`.slice(0, 2500)}\``)]})
//(client.channels.resolve(client.config.mainServer.channels.errors) as Discord.TextChannel).send({embeds: [new client.embed().setColor('#420420').setTitle('Error caught!').setDescription(`**Error:** \`${error.message}\`\n\n**Stack:** \`${`${error.stack}`.slice(0, 2500)}\``)]})
});
process.on('error', async(error: Error)=>{
console.log(error);
(client.channels.resolve(client.config.mainServer.channels.errors) as Discord.TextChannel).send({embeds: [new client.embed().setColor('#420420').setTitle('Error caught!').setDescription(`**Error:** \`${error.message}\`\n\n**Stack:** \`${`${error.stack}`.slice(0, 2500)}\``)]})
//(client.channels.resolve(client.config.mainServer.channels.errors) as Discord.TextChannel).send({embeds: [new client.embed().setColor('#420420').setTitle('Error caught!').setDescription(`**Error:** \`${error.message}\`\n\n**Stack:** \`${`${error.stack}`.slice(0, 2500)}\``)]})
});
// Daggerwin MP loop
setInterval(async()=>{
if (!client.config.botSwitches.mpstats) return;
const msg = await (client.channels.resolve('904192878140608563') as Discord.TextChannel).messages.fetch('1042464209709051974')
const msg = await (client.channels.resolve('904192878140608563') as Discord.TextChannel).messages.fetch('1042835699906400346')
const embed = new client.embed();
let Players = [];
let Server: any;
@ -115,7 +121,7 @@ setInterval(async()=>{
} else {
const embed1 = new client.embed().setColor(client.config.embedColor).setTitle('Server details').addFields(
{name: 'Current Map', value: `${Server.data.server.mapName.length == 0 ? '\u200b' : Server.data.server.mapName}`, inline: true},
{name: 'Game Version', value: `${Server.data.server.version.length == 0 ? '\u200b' : Server.data.server.version}`, inline: true},
{name: 'Version', value: `${Server.data.server.version.length == 0 ? '\u200b' : Server.data.server.version}`, inline: true},
{name: 'In-game Time', value: `${('0' + Math.floor((Server.data.server.dayTime/3600/1000))).slice(-2)}:${('0' + Math.floor((Server.data.server.dayTime/60/1000)%60)).slice(-2)}`, inline: true},
{name: 'Slot Usage', value: `${Number(xmlData?.slotSystem?._attributes?.slotUsage).toLocaleString('en-US')}`, inline: true},
{name: 'Timescale', value: `${formatNumber(timeScale, 0, 'x')}`, inline: true}
@ -131,7 +137,7 @@ setInterval(async()=>{
// YouTube Upload notification
setInterval(async()=>{
client.YTLoop('UCQ8k8yTDLITldfWYKDs3xFg', 'Daggerwin', '528967918772551702'); // 528967918772551702 = #videos-and-streams
client.YTLoop('UCQ8k8yTDLITldfWYKDs3xFg', 'Daggerwin', '904192878140608563'); // 528967918772551702 = #videos-and-streams
client.YTLoop('UCguI73--UraJpso4NizXNzA', 'Machinery Restorer', '767444045520961567') // 767444045520961567 = #machinery-restorer
}, 300000)
@ -159,7 +165,7 @@ setInterval(async()=>{
total = yesterday
}
dailyMsgs.push([formattedDate, total]);
fs.writeFileSync(__dirname + 'dailyMsgs.json', JSON.stringify(dailyMsgs))
fs.writeFileSync(__dirname + '/database/dailyMsgs.json', JSON.stringify(dailyMsgs))
console.log(`\x1b[36m[${client.moment().format('DD/MM/YY HH:mm:ss')}] \x1b[33m`, `Pushed [${formattedDate}, ${total}] to dailyMsgs`)
}
}, 5000)

View File

@ -1,18 +1,18 @@
interface formatTimeOpt {
export interface formatTimeOpt {
longNames: boolean,
commas: boolean
}
interface createTableOpt {
export interface createTableOpt {
columnAlign: any,
columnSeparator: any,
columnEmptyChar: any
}
interface punOpt {
export interface punOpt {
time?: string,
reason?: string,
interaction?: any
}
interface Punishment {
export interface Punishment {
id: number;
type: string;
member: string;

View File

@ -1,5 +1,4 @@
{
"ts-node": {
"transpileOnly": true,
"compilerOptions": {
"esModuleInterop": true,
@ -12,11 +11,8 @@
"rootDir": "src/",
"outDir": "dist/",
"moduleResolution": "Node",
"declarationDir": "src/typings",
"typeRoots": [ "node_modules/@types", "src/typings" ],
"typeRoots": [ "node_modules/@types", "./src/typings" ],
},
},
"include": [ "node_modules/@types", "src/**/*" ],
"exclude": [ "dist", "node_modules" ],
}