mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-24 20:19:49 +02:00
feat: /stats
This commit is contained in:
1 parent
bf7993fa38
commit
4482b76746
8 files changed
+192
-37
No files matched your search
Vendored
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"cSpell.words": ["Abhi", "accountinfo", "SKLLD", "wargaming"],
|
"cSpell.words": ["Abhi", "accountinfo", "SKLLD", "wargaming", "winrate"],
|
||||||
"deno.enable": false,
|
"deno.enable": false,
|
||||||
"deno.unstable": false
|
"deno.unstable": false
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import { faker } from '@faker-js/faker';
|
import { faker } from '@faker-js/faker';
|
||||||
import { EmbedBuilder, GuildMember, TextChannel } from 'discord.js';
|
import { EmbedBuilder, GuildMember, TextChannel } from 'discord.js';
|
||||||
import discord from '../../discord.json' assert { type: 'json' };
|
import discord from '../../discord.json' assert { type: 'json' };
|
||||||
|
import { SKILLED_COLOR } from '../constants/colors.js';
|
||||||
|
|
||||||
export default async function (member: GuildMember) {
|
export default async function (member: GuildMember) {
|
||||||
console.log(`${member.user.tag} joined`);
|
console.log(`${member.user.tag} joined`);
|
||||||
@@ -10,7 +11,7 @@ export default async function (member: GuildMember) {
|
|||||||
).send({
|
).send({
|
||||||
embeds: [
|
embeds: [
|
||||||
new EmbedBuilder()
|
new EmbedBuilder()
|
||||||
.setColor('#8e3cf5')
|
.setColor(SKILLED_COLOR)
|
||||||
.setTitle(`Welcome ${member.user.username}`)
|
.setTitle(`Welcome ${member.user.username}`)
|
||||||
.setDescription(
|
.setDescription(
|
||||||
`Welcome to the Skilled server, **${
|
`Welcome to the Skilled server, **${
|
||||||
|
|||||||
+75
-2
@@ -1,14 +1,88 @@
|
|||||||
import {
|
import {
|
||||||
CacheType,
|
CacheType,
|
||||||
ChatInputCommandInteraction,
|
ChatInputCommandInteraction,
|
||||||
|
EmbedBuilder,
|
||||||
SlashCommandBuilder,
|
SlashCommandBuilder,
|
||||||
} from 'discord.js';
|
} from 'discord.js';
|
||||||
|
import fetch from 'node-fetch';
|
||||||
|
import { SKILLED_COLOR } from '../constants/colors.js';
|
||||||
import { SERVERS } from '../constants/servers.js';
|
import { SERVERS } from '../constants/servers.js';
|
||||||
|
import { PlayerStatistics } from '../types/statistics.js';
|
||||||
|
import getBlitzAccount from '../utilities/getBlitzAccount.js';
|
||||||
|
|
||||||
export async function execute(
|
export async function execute(
|
||||||
interaction: ChatInputCommandInteraction<CacheType>,
|
interaction: ChatInputCommandInteraction<CacheType>,
|
||||||
) {
|
) {
|
||||||
interaction.reply('YOU SUCK MORON GO PLAY ROBLOX');
|
const ign = interaction.options.getString('ign')!;
|
||||||
|
const server = interaction.options.getString(
|
||||||
|
'server',
|
||||||
|
) as keyof typeof SERVERS;
|
||||||
|
const period = interaction.options.getString('period')! as
|
||||||
|
| '30'
|
||||||
|
| '90'
|
||||||
|
| 'career';
|
||||||
|
|
||||||
|
getBlitzAccount(interaction, ign, server, async (account) => {
|
||||||
|
const data = (await (
|
||||||
|
await fetch(
|
||||||
|
`https://www.blitzstars.com/api/top/player/${account.account_id}`,
|
||||||
|
)
|
||||||
|
).json()) as PlayerStatistics;
|
||||||
|
const stats =
|
||||||
|
period === 'career' ? data.statistics : data[`period${period}d`];
|
||||||
|
|
||||||
|
interaction.reply({
|
||||||
|
embeds: [
|
||||||
|
new EmbedBuilder()
|
||||||
|
.setColor(SKILLED_COLOR)
|
||||||
|
.setTitle(
|
||||||
|
`${data.nickname}'s ${
|
||||||
|
period === 'career' ? period : `${period} day`
|
||||||
|
} stats`,
|
||||||
|
)
|
||||||
|
.setDescription(
|
||||||
|
`${[
|
||||||
|
['Winrate', `${stats.special.winrate.toFixed(2)}%`],
|
||||||
|
['Survival', `${stats.special.survivalRate.toFixed(2)}%`],
|
||||||
|
[
|
||||||
|
'Accuracy',
|
||||||
|
`${((stats.all.hits / stats.all.shots) * 100).toFixed(2)}%`,
|
||||||
|
],
|
||||||
|
['WN8', stats.wn8.toFixed(0)],
|
||||||
|
['WN7', stats.wn7.toFixed(0)],
|
||||||
|
[],
|
||||||
|
['Battles', stats.all.battles],
|
||||||
|
['Wins', stats.all.wins],
|
||||||
|
['Losses', stats.all.losses],
|
||||||
|
['Average tier', stats.avg_tier.toFixed(2)],
|
||||||
|
[],
|
||||||
|
['Hits per battle', stats.special.hpb.toFixed(0)],
|
||||||
|
['Damage per battle', stats.special.dpb.toFixed(0)],
|
||||||
|
['Kills per battle', stats.special.kpb.toFixed(2)],
|
||||||
|
['Spots per battle', stats.special.spb.toFixed(2)],
|
||||||
|
[
|
||||||
|
'Shots per battle',
|
||||||
|
(stats.all.shots / stats.all.battles).toFixed(2),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'Hits per battle',
|
||||||
|
(stats.all.hits / stats.all.battles).toFixed(2),
|
||||||
|
],
|
||||||
|
['XP per battle', (stats.all.xp / stats.all.battles).toFixed(2)],
|
||||||
|
[],
|
||||||
|
['Damage ratio', stats.special.damageRatio.toFixed(2)],
|
||||||
|
['Kills to death ratio', stats.special.kdr.toFixed(2)],
|
||||||
|
]
|
||||||
|
.map((array) =>
|
||||||
|
array.length === 0 ? '' : `**${array[0]}**: ${array[1]}`,
|
||||||
|
)
|
||||||
|
.join(
|
||||||
|
'\n',
|
||||||
|
)}\n\nPowered by [BlitzStars](https://www.blitzstars.com/)`,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export const data = new SlashCommandBuilder()
|
export const data = new SlashCommandBuilder()
|
||||||
@@ -37,7 +111,6 @@ export const data = new SlashCommandBuilder()
|
|||||||
.setDescription('The last number of days of stats')
|
.setDescription('The last number of days of stats')
|
||||||
.setChoices(
|
.setChoices(
|
||||||
{ name: '30 Days', value: '30' },
|
{ name: '30 Days', value: '30' },
|
||||||
{ name: '60 Days', value: '60' },
|
|
||||||
{ name: '90 Days', value: '90' },
|
{ name: '90 Days', value: '90' },
|
||||||
{ name: 'Career', value: 'career' },
|
{ name: 'Career', value: 'career' },
|
||||||
)
|
)
|
||||||
|
|||||||
+11
-32
@@ -6,8 +6,9 @@ import {
|
|||||||
} from 'discord.js';
|
} from 'discord.js';
|
||||||
import fetch from 'node-fetch';
|
import fetch from 'node-fetch';
|
||||||
import discord from '../../discord.json' assert { type: 'json' };
|
import discord from '../../discord.json' assert { type: 'json' };
|
||||||
|
import { NEGATIVE_COLOR, POSITIVE_COLOR } from '../constants/colors.js';
|
||||||
import { SERVERS } from '../constants/servers.js';
|
import { SERVERS } from '../constants/servers.js';
|
||||||
import AccountList from '../types/accountList.js';
|
import getBlitzAccount from '../utilities/getBlitzAccount.js';
|
||||||
|
|
||||||
export const disabled = true;
|
export const disabled = true;
|
||||||
|
|
||||||
@@ -15,20 +16,18 @@ export async function execute(
|
|||||||
interaction: ChatInputCommandInteraction<CacheType>,
|
interaction: ChatInputCommandInteraction<CacheType>,
|
||||||
) {
|
) {
|
||||||
const ign = interaction.options.getString('ign')!;
|
const ign = interaction.options.getString('ign')!;
|
||||||
const server = interaction.options.getString('server')!;
|
const server = interaction.options.getString(
|
||||||
const serverName = SERVERS[server as keyof typeof SERVERS];
|
'server',
|
||||||
const players = (await fetch(
|
) as keyof typeof SERVERS;
|
||||||
`https://api.wotblitz.${server}/wotb/account/list/?application_id=${process.env.WARGAMING_APPLICATION_ID}&search=${ign}`,
|
|
||||||
).then((response) => response.json())) as AccountList;
|
|
||||||
|
|
||||||
if (players?.data?.[0]?.nickname === ign) {
|
getBlitzAccount(interaction, ign, server, async (account) => {
|
||||||
// good match
|
// good match
|
||||||
const clanData = (await fetch(
|
const clanData = (await fetch(
|
||||||
`https://api.wotblitz.${server}/wotb/clans/accountinfo/?application_id=${process.env.WARGAMING_APPLICATION_ID}&account_id=${players.data[0].account_id}&extra=clan`,
|
`https://api.wotblitz.${server}/wotb/clans/accountinfo/?application_id=${process.env.WARGAMING_APPLICATION_ID}&account_id=${account.account_id}&extra=clan`,
|
||||||
).then((response) => response.json())) as {
|
).then((response) => response.json())) as {
|
||||||
data: { [key: number]: { clan: { tag: string } | null } };
|
data: { [key: number]: { clan: { tag: string } | null } };
|
||||||
};
|
};
|
||||||
const clan = clanData.data[players.data[0].account_id].clan;
|
const clan = clanData.data[account.account_id].clan;
|
||||||
const clanTag = clan === null ? '' : ` [${clan.tag}]`;
|
const clanTag = clan === null ? '' : ` [${clan.tag}]`;
|
||||||
|
|
||||||
if (interaction.member && interaction.guild) {
|
if (interaction.member && interaction.guild) {
|
||||||
@@ -44,7 +43,7 @@ export async function execute(
|
|||||||
await interaction.reply({
|
await interaction.reply({
|
||||||
embeds: [
|
embeds: [
|
||||||
new EmbedBuilder()
|
new EmbedBuilder()
|
||||||
.setColor('#82ff29')
|
.setColor(POSITIVE_COLOR)
|
||||||
.setTitle(`${interaction.user.username} is verified`)
|
.setTitle(`${interaction.user.username} is verified`)
|
||||||
.setDescription(`The user is now verified as ${ign}${clanTag}`),
|
.setDescription(`The user is now verified as ${ign}${clanTag}`),
|
||||||
],
|
],
|
||||||
@@ -58,7 +57,7 @@ export async function execute(
|
|||||||
await interaction.reply({
|
await interaction.reply({
|
||||||
embeds: [
|
embeds: [
|
||||||
new EmbedBuilder()
|
new EmbedBuilder()
|
||||||
.setColor('#ff4747')
|
.setColor(NEGATIVE_COLOR)
|
||||||
.setTitle(`${interaction.user.username} failed to verify`)
|
.setTitle(`${interaction.user.username} failed to verify`)
|
||||||
.setDescription(
|
.setDescription(
|
||||||
'I may not have the permission to change your nickname.',
|
'I may not have the permission to change your nickname.',
|
||||||
@@ -71,27 +70,7 @@ export async function execute(
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
});
|
||||||
// no exact match
|
|
||||||
interaction.reply({
|
|
||||||
embeds: [
|
|
||||||
new EmbedBuilder()
|
|
||||||
.setColor('#ff4747')
|
|
||||||
.setTitle(`Account not found`)
|
|
||||||
.setDescription(
|
|
||||||
`Are you sure your username is exactly "${ign}" in the ${serverName} server? I found ${
|
|
||||||
players?.data
|
|
||||||
? players.data.length < 100
|
|
||||||
? players.data.length
|
|
||||||
: 'over 100'
|
|
||||||
: 'no'
|
|
||||||
} similarly spelled account${
|
|
||||||
players?.data?.length !== 1 ? 's' : ''
|
|
||||||
}. Try re-running the command. Don't make typos and capitalize correctly.`,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const data = new SlashCommandBuilder()
|
export const data = new SlashCommandBuilder()
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export const SKILLED_COLOR = '#8e3cf5';
|
||||||
|
export const POSITIVE_COLOR = '#82ff29';
|
||||||
|
export const NEGATIVE_COLOR = '#ff4747';
|
||||||
@@ -1,6 +1,11 @@
|
|||||||
|
export interface Account {
|
||||||
|
nickname: string;
|
||||||
|
account_id: number;
|
||||||
|
}
|
||||||
|
|
||||||
type AccountList =
|
type AccountList =
|
||||||
| {
|
| {
|
||||||
data?: { nickname: string; account_id: number }[];
|
data?: Account[];
|
||||||
}
|
}
|
||||||
| undefined;
|
| undefined;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
export interface PeriodStatistics {
|
||||||
|
all: {
|
||||||
|
spotted: number;
|
||||||
|
hits: number;
|
||||||
|
frags: number;
|
||||||
|
wins: number;
|
||||||
|
losses: number;
|
||||||
|
capture_points: number;
|
||||||
|
battles: number;
|
||||||
|
damage_dealt: number;
|
||||||
|
damage_received: number;
|
||||||
|
shots: number;
|
||||||
|
frags8p: number;
|
||||||
|
xp: number;
|
||||||
|
win_and_survived: number;
|
||||||
|
survived_battles: number;
|
||||||
|
dropped_capture_points: number;
|
||||||
|
};
|
||||||
|
special: {
|
||||||
|
winrate: number;
|
||||||
|
damageRatio: number;
|
||||||
|
kdr: number;
|
||||||
|
dpb: number;
|
||||||
|
kpb: number;
|
||||||
|
hpb: number;
|
||||||
|
spb: number;
|
||||||
|
hitRate: number;
|
||||||
|
survivalRate: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
wn7: number;
|
||||||
|
wn8: number;
|
||||||
|
avg_tier: number;
|
||||||
|
pwp: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PlayerStatistics {
|
||||||
|
statistics: PeriodStatistics;
|
||||||
|
period30d: PeriodStatistics;
|
||||||
|
period90d: PeriodStatistics;
|
||||||
|
|
||||||
|
_id: string;
|
||||||
|
nickname: string;
|
||||||
|
nickname_lowercase: string;
|
||||||
|
region: string;
|
||||||
|
last_battle_time: number;
|
||||||
|
__v: number;
|
||||||
|
updatedAt: string;
|
||||||
|
createdAt: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import {
|
||||||
|
CacheType,
|
||||||
|
ChatInputCommandInteraction,
|
||||||
|
EmbedBuilder,
|
||||||
|
} from 'discord.js';
|
||||||
|
import { NEGATIVE_COLOR } from '../constants/colors.js';
|
||||||
|
import { SERVERS } from '../constants/servers.js';
|
||||||
|
import AccountList, { Account } from '../types/accountList.js';
|
||||||
|
|
||||||
|
export default async function getBlitzAccount(
|
||||||
|
interaction: ChatInputCommandInteraction<CacheType>,
|
||||||
|
ign: string,
|
||||||
|
server: keyof typeof SERVERS,
|
||||||
|
callback: (account: Account) => void,
|
||||||
|
) {
|
||||||
|
const serverName = SERVERS[server];
|
||||||
|
const players = (await fetch(
|
||||||
|
`https://api.wotblitz.${server}/wotb/account/list/?application_id=${process.env.WARGAMING_APPLICATION_ID}&search=${ign}`,
|
||||||
|
).then((response) => response.json())) as AccountList;
|
||||||
|
|
||||||
|
if (players?.data?.[0]?.nickname === ign) {
|
||||||
|
callback(players.data[0]);
|
||||||
|
} else {
|
||||||
|
// no exact match
|
||||||
|
interaction.reply({
|
||||||
|
embeds: [
|
||||||
|
new EmbedBuilder()
|
||||||
|
.setColor(NEGATIVE_COLOR)
|
||||||
|
.setTitle(`Account not found`)
|
||||||
|
.setDescription(
|
||||||
|
`Are you sure your username is exactly "${ign}" in the ${serverName} server? I found ${
|
||||||
|
players?.data
|
||||||
|
? players.data.length < 100
|
||||||
|
? players.data.length
|
||||||
|
: 'over 100'
|
||||||
|
: 0
|
||||||
|
} similarly spelled account${
|
||||||
|
players?.data?.length !== 1 ? 's' : ''
|
||||||
|
}. Try re-running the command. Don't make typos and capitalize correctly.`,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user