@ -1,281 +1,324 @@ // 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, ], }); console.log('Attempting to log in...'); client.once('ready', () => { 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); }); // 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/${encodeURIComponent( username )}` ); return response.data; } catch (error) { console.error('Error fetching user data:', error); return null; } } // Function to get badge image URL function getBadgeImageUrl(badgeName) { if (!badgeName) { return 'https://www.vrbattles.gg/assets/images/badges/xp_badges/A/BADGE_A1_72p.png'; } badgeName = badgeName.toUpperCase().replace(/ /g, '_'); let badgeUrl = 'https://www.vrbattles.gg/assets/images/badges/xp_badges/'; if (badgeName.startsWith('A')) { badgeUrl += 'A/'; } else if (badgeName.startsWith('B')) { badgeUrl += 'B/'; } else if (badgeName.startsWith('C')) { badgeUrl += 'C/'; } else { badgeUrl += 'A/'; } badgeUrl += `BADGE_${badgeName}_72p.png`; return badgeUrl; } // Interaction handler client.on('interactionCreate', async (interaction) => { if (!interaction.isCommand()) return; const { commandName } = interaction; if (commandName === 'ping') { 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') { try { playerData = JSON.parse(userData.player_data); } catch (error) { await interaction.editReply('Error parsing player data.'); return; } } else { playerData = userData.player_data; } if (!playerData || !playerData.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'}`) .setColor('#0099ff'); // Set thumbnail if avatar is available if (user.avatar) { embed.setThumbnail( `https://www.vrbattles.gg/assets/uploads/profile/${user.avatar}` ); } // Before adding fields to the embed, initialize a counter let totalFields = 0; // 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); totalFields += profileFields.length; } // 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 && totalFields < 25) { if (totalFields + 1 <= 25) { embed.addFields({ name: '\u200B', value: '**Game Statistics**' }); totalFields += 1; } 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, }); // Calculate the number of fields to be added const fieldsToAdd = 1 + statsFields.length; // 1 for the section header // Check if adding these fields would exceed the limit if (totalFields + fieldsToAdd > 25) { // You can choose to skip adding these fields or break the loop break; // Stops adding more fields } // Add the section header embed.addFields({ name: '\u200B', value: `**${gameName} - ${modeName}**`, }); totalFields += 1; // Add the stats fields embed.addFields(statsFields); totalFields += statsFields.length; // Check after each addition if (totalFields >= 25) { break; } } if (totalFields >= 25) { break; } } } // Add teams dynamically const teams = playerData.teams; if (teams && Object.keys(teams).length > 0 && totalFields < 25) { const teamList = Object.values(teams) .map( (team) => `- **${team.team_name}** (${team.game_name} - ${team.game_mode})` ) .join('\n'); const teamsField = [ { name: '\u200B', value: '**Teams**' }, { name: 'Team List', value: teamList || 'No teams available' }, ]; // Check if adding these fields would exceed the limit const fieldsToAdd = teamsField.length; if (totalFields + fieldsToAdd <= 25) { embed.addFields(teamsField); totalFields += fieldsToAdd; } } // Add recent matches dynamically const matches = playerData.matches; if (matches && Object.keys(matches).length > 0 && totalFields < 25) { 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'); const matchesField = [ { name: '\u200B', value: '**Recent Matches**' }, { name: 'Match History', value: matchList || 'No recent matches' }, ]; // Check if adding these fields would exceed the limit const fieldsToAdd = matchesField.length; if (totalFields + fieldsToAdd <= 25) { embed.addFields(matchesField); totalFields += fieldsToAdd; } } // 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.' ); } } });