diff --git a/deploy-commands.js b/deploy-commands.js index 2fa15df..635ff80 100644 --- a/deploy-commands.js +++ b/deploy-commands.js @@ -1,3 +1,5 @@ +// deploycommands.js + const { REST, Routes, SlashCommandBuilder } = require('discord.js'); require('dotenv').config(); @@ -11,7 +13,11 @@ const commands = [ .addStringOption(option => option.setName('username') .setDescription('The username to search for') - .setRequired(true)), + .setRequired(true)) + .addStringOption(option => + option.setName('game') + .setDescription('Specify a game to view stats for') + .setRequired(false)), // Add more commands here ]; @@ -20,11 +26,11 @@ const rest = new REST({ version: '10' }).setToken(process.env.BOT_TOKEN); (async () => { try { console.log('Started refreshing application (/) commands.'); - console.log('Commands to be deployed:', commands); + console.log('Commands to be deployed:', commands.map(cmd => cmd.name)); await rest.put( Routes.applicationCommands(process.env.CLIENT_ID), - { body: commands }, + { body: commands.map(command => command.toJSON()) }, ); console.log('Successfully reloaded application (/) commands.'); diff --git a/index.js b/index.js index 9a6c8a3..36a3b6d 100644 --- a/index.js +++ b/index.js @@ -1,67 +1,46 @@ -const { Client, GatewayIntentBits, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, REST, Routes, SlashCommandBuilder } = require('discord.js'); +// index.js + +const { + Client, + GatewayIntentBits, + EmbedBuilder, + ActionRowBuilder, + ButtonBuilder, + ButtonStyle, +} = require('discord.js'); const axios = require('axios'); require('dotenv').config(); console.log('Starting bot...'); const client = new Client({ - intents: [ - GatewayIntentBits.Guilds, - GatewayIntentBits.GuildMessages, - GatewayIntentBits.MessageContent - ] + intents: [ + GatewayIntentBits.Guilds, + GatewayIntentBits.GuildMessages, + GatewayIntentBits.MessageContent, + ], }); console.log('Attempting to log in...'); client.once('ready', () => { - console.log(`Logged in as ${client.user.tag}!`); + console.log(`Logged in as ${client.user.tag}!`); }); client.login(process.env.BOT_TOKEN).then(() => { - console.log('Login successful'); -}).catch(error => { - console.error('Login failed:', error); + console.log('Login successful'); +}).catch((error) => { + console.error('Login failed:', error); }); -// Remove the second login call -// client.login(process.env.BOT_TOKEN); - -// Register Slash Commands -const commands = [ - new SlashCommandBuilder() - .setName('ping') - .setDescription('Replies with Pong!'), - new SlashCommandBuilder() - .setName('finduser') - .setDescription('Find a user by username') - .addStringOption(option => - option.setName('username') - .setDescription('The username to search for') - .setRequired(true)) -]; - -const rest = new REST({ version: '10' }).setToken(process.env.BOT_TOKEN); - -(async () => { - try { - console.log('Started refreshing application (/) commands.'); - - await rest.put( - Routes.applicationCommands(client.user.id), - { body: commands }, - ); - - console.log('Successfully reloaded application (/) commands.'); - } catch (error) { - console.error(error); - } -})(); - -// Function to fetch user data +// Function to fetch user data from the API async function findUserByUsername(username) { try { - const response = await axios.get(`https://www.vrbattles.gg/api/get_player_data_by_username/${username}`); + const response = await axios.get( + `https://www.vrbattles.gg/api/get_player_data_by_username/${encodeURIComponent( + username + )}` + ); return response.data; } catch (error) { console.error('Error fetching user data:', error); @@ -89,12 +68,11 @@ function getBadgeImageUrl(badgeName) { } badgeUrl += `BADGE_${badgeName}_72p.png`; - console.log('Badge URL:', badgeUrl); return badgeUrl; } // Interaction handler -client.on('interactionCreate', async interaction => { +client.on('interactionCreate', async (interaction) => { if (!interaction.isCommand()) return; const { commandName } = interaction; @@ -103,10 +81,13 @@ client.on('interactionCreate', async interaction => { await interaction.reply('Pong!'); } else if (commandName === 'finduser') { const username = interaction.options.getString('username'); - + const gameFilter = interaction.options.getString('game'); + await interaction.deferReply(); + // Fetch data from the API using the provided username const userData = await findUserByUsername(username); + if (userData && userData.success) { let playerData; if (typeof userData.player_data === 'string') { @@ -121,46 +102,179 @@ client.on('interactionCreate', async interaction => { } if (!playerData || !playerData.profile) { - await interaction.editReply('User found but profile data is null. They need to log in to VRBattles to update their profile.'); + await interaction.editReply( + 'User found but profile data is unavailable. They may need to log in to VRBattles to update their profile.' + ); return; } const user = playerData.profile || {}; const badgeImageUrl = getBadgeImageUrl(user.current_level_badge); + // Create the embed builder const embed = new EmbedBuilder() .setTitle(`User: ${playerData.username || 'Unknown'}`) .setDescription(`Bio: ${user.bio || 'No bio available'}`) - .addFields( - { name: 'Country', value: user.country || 'Unknown', inline: true }, - { name: 'Rank', value: user.rank || 'Unranked', inline: true }, - { name: 'Level', value: user.level?.toString() || 'N/A', inline: true }, - { name: 'Prestige', value: user.prestige?.toString() || '0', inline: true }, - { name: 'Total XP', value: user.xp?.toString() || '0', inline: true } - ) - .setImage(badgeImageUrl) - .addFields({ name: 'XP Badge', value: ' ' }) .setColor('#0099ff'); + // Set thumbnail if avatar is available if (user.avatar) { - embed.setThumbnail(`https://www.vrbattles.gg/assets/uploads/profile/${user.avatar}`); + embed.setThumbnail( + `https://www.vrbattles.gg/assets/uploads/profile/${user.avatar}` + ); } - const row = new ActionRowBuilder() - .addComponents( - new ButtonBuilder() - .setLabel('🔵 View Profile') - .setStyle(ButtonStyle.Link) - .setURL(`https://www.vrbattles.gg/profile/${playerData.username}`), - new ButtonBuilder() - .setLabel('🟡 Join Discord') - .setStyle(ButtonStyle.Link) - .setURL('https://discord.gg/j3DKVATPGQ') // Replace with your Discord invite URL + // Add profile fields dynamically + const profileFields = []; + + if (user.country) + profileFields.push({ + name: 'Country', + value: user.country, + inline: true, + }); + if (user.rank) + profileFields.push({ name: 'Rank', value: user.rank, inline: true }); + if (user.level) + profileFields.push({ + name: 'Level', + value: user.level.toString(), + inline: true, + }); + if (user.prestige) + profileFields.push({ + name: 'Prestige', + value: user.prestige.toString(), + inline: true, + }); + if (user.xp) + profileFields.push({ + name: 'Total XP', + value: user.xp.toString(), + inline: true, + }); + + if (profileFields.length > 0) { + embed.addFields(profileFields); + } + + // Set badge image if available + if (badgeImageUrl) { + embed.setImage(badgeImageUrl); + } + + // Dynamically add game statistics + const games = playerData.stats?.games; + if (games && Object.keys(games).length > 0) { + embed.addFields({ name: '\u200B', value: '**Game Statistics**' }); + + for (const [gameName, gameData] of Object.entries(games)) { + if ( + gameFilter && + gameName.toLowerCase() !== gameFilter.toLowerCase() + ) { + continue; // Skip games that don't match the filter + } + + for (const [modeName, modeStats] of Object.entries(gameData)) { + const statsFields = []; + + // Collect stats for the mode + if (modeStats.matches) + statsFields.push({ + name: 'Matches', + value: modeStats.matches.toString(), + inline: true, + }); + if (modeStats.wins) + statsFields.push({ + name: 'Wins', + value: modeStats.wins.toString(), + inline: true, + }); + if (modeStats.losses) + statsFields.push({ + name: 'Losses', + value: modeStats.losses.toString(), + inline: true, + }); + if (modeStats.win_rate) + statsFields.push({ + name: 'Win Rate', + value: modeStats.win_rate, + inline: true, + }); + if (modeStats.mmr) + statsFields.push({ + name: 'MMR', + value: modeStats.mmr.toString(), + inline: true, + }); + + if (statsFields.length > 0) { + embed.addFields( + { name: '\u200B', value: `**${gameName} - ${modeName}**` }, + ...statsFields + ); + } + } + } + } + + // Add teams dynamically + const teams = playerData.teams; + if (teams && Object.keys(teams).length > 0) { + const teamList = Object.values(teams) + .map( + (team) => + `- **${team.team_name}** (${team.game_name} - ${team.game_mode})` + ) + .join('\n'); + + embed.addFields( + { name: '\u200B', value: '**Teams**' }, + { name: 'Team List', value: teamList || 'No teams available' } ); + } + + // Add recent matches dynamically + const matches = playerData.matches; + if (matches && Object.keys(matches).length > 0) { + const matchList = Object.values(matches) + .sort((a, b) => new Date(b.start_time) - new Date(a.start_time)) // Sort by date descending + .slice(0, 3) // Limit to recent 3 matches + .map((match) => { + const date = new Date(match.start_time).toLocaleDateString(); + const team1 = match.team1_name || 'Team 1'; + const team2 = match.team2_name || 'Team 2'; + const score = match.score || 'N/A'; + return `- **${team1}** vs **${team2}** on ${date} - Result: ${score}`; + }) + .join('\n'); + + embed.addFields( + { name: '\u200B', value: '**Recent Matches**' }, + { name: 'Match History', value: matchList || 'No recent matches' } + ); + } + + // Add action buttons + const row = new ActionRowBuilder().addComponents( + new ButtonBuilder() + .setLabel('🔵 View Profile') + .setStyle(ButtonStyle.Link) + .setURL(`https://www.vrbattles.gg/profile/${playerData.username}`), + new ButtonBuilder() + .setLabel('🟡 Join Discord') + .setStyle(ButtonStyle.Link) + .setURL('https://discord.gg/j3DKVATPGQ') // Replace with your Discord invite URL + ); await interaction.editReply({ embeds: [embed], components: [row] }); } else { - await interaction.editReply('User not found or an error occurred while fetching data.'); + await interaction.editReply( + 'User not found or an error occurred while fetching data.' + ); } } }); \ No newline at end of file