2022-05-13 17:01:16 +00:00
const { SlashCommandBuilder } = require ( '@discordjs/builders' ) ;
const { parse } = require ( "csv-parse/sync" ) ;
const fs = require ( 'node:fs' ) ;
const noblox = require ( "noblox.js" ) ;
2022-10-22 04:04:23 +00:00
const axios = require ( "axios" ) . default ;
2024-04-15 08:13:32 +00:00
const { submissions , commands , cookies } = require ( "../config/config.js" ) ;
2022-07-12 02:09:07 +00:00
async function robloxUserFromDiscord ( id ) {
if ( isNaN ( id ) ) return undefined ;
try {
2022-10-22 04:04:23 +00:00
const res = await axios . get ( ` https://api.fiveman1.net/v1/users/ ${ id } ` ) ;
return res . data . result . robloxId ;
2022-07-12 02:09:07 +00:00
} catch ( error ) {
return undefined ;
}
}
async function robloxUsernameFromId ( id ) {
if ( isNaN ( id ) ) return undefined ;
try {
2022-10-22 04:04:23 +00:00
const res = await axios . get ( ` https://users.roblox.com/v1/users/ ${ id } ` ) ;
return res . data . name ;
2022-07-12 02:09:07 +00:00
} catch ( error ) {
return undefined ;
}
}
2022-05-13 17:01:16 +00:00
async function execute ( interaction ) {
2022-10-22 04:04:23 +00:00
const userId = await robloxUserFromDiscord ( interaction . user . id ) ;
2022-07-12 02:09:07 +00:00
if ( ! userId ) {
2022-10-22 04:04:23 +00:00
const msg = "You don't have a Roblox account linked with your Discord account. Use !link with rbhop dog to link your account." ;
2022-07-12 02:09:07 +00:00
await interaction . reply ( { content : msg , ephemeral : true } ) ;
return ;
}
2022-05-13 17:01:16 +00:00
const game = interaction . options . getString ( "game" ) ;
2023-03-08 20:37:40 +00:00
const fname = submissions [ game ] ;
if ( fname === undefined ) {
2022-05-13 17:01:16 +00:00
await interaction . reply ( { content : "Invalid game specified!" , ephemeral : true } ) ;
return ;
}
if ( ! fs . existsSync ( fname ) ) {
fs . writeFileSync ( fname , "id,timestamp\n" ) ;
}
const id = interaction . options . getInteger ( "asset_id" ) ;
2024-04-15 08:13:32 +00:00
await noblox . setCookie ( cookies [ game ] ) ;
// Check that the bot owns this model
if ( ! ( await noblox . getOwnership ( ( await noblox . getCurrentUser ( ) ) . UserID , id , "Asset" ) ) ) {
const msg = ` The ${ game } maptest bot's inventory does not contain this asset (id: ${ id } ). You must use the /take command first. ` ;
await interaction . reply ( { content : msg , ephemeral : true } ) ;
return ;
}
2022-05-13 17:01:16 +00:00
try {
2024-04-15 08:13:32 +00:00
const info = await noblox . getProductInfo ( id ) ;
2022-05-13 17:01:16 +00:00
if ( info . AssetTypeId != 10 ) {
await interaction . reply ( { content : ` (id: ${ id } ) is not a valid model ID. ` , ephemeral : true } ) ;
return ;
}
2022-07-12 02:09:07 +00:00
if ( info . Creator . Id != userId ) {
const assetUsername = await robloxUsernameFromId ( info . Creator . Id ) ;
const interactionUsername = await robloxUsernameFromId ( userId ) ;
2024-04-15 08:13:32 +00:00
const msg = ` The account linked to your Discord ( ${ interactionUsername } ) is not the owner of this model ( ${ assetUsername } ), so you cannot submit it. ` ;
2022-07-12 02:09:07 +00:00
await interaction . reply ( { content : msg , ephemeral : true } ) ;
2024-04-15 08:13:32 +00:00
return ;
2022-07-12 02:09:07 +00:00
}
2022-05-13 17:01:16 +00:00
} catch ( error ) {
2024-04-15 08:13:32 +00:00
// Roblox only lets you call the product info API like once per 30 seconds for some reason...
if ( error . message . startsWith ( "429" ) ) {
await interaction . reply ( { content : ` The maptest bot is being rate-limited by Roblox, please wait a minute before doing this command again. ` , ephemeral : true } ) ;
return ;
}
2022-05-13 17:01:16 +00:00
console . log ( error ) ;
await interaction . reply ( { content : ` There is a problem with this asset ID (id: ${ id } ). ` , ephemeral : true } ) ;
return ;
}
const csv = fs . readFileSync ( fname ) ;
const records = parse ( csv , { delimiter : ',' , fromLine : 2 } ) ;
let s = "id,timestamp\n" ;
for ( let record of records ) {
const rid = record [ 0 ] ;
const rtimestamp = record [ 1 ] ;
if ( id == rid ) {
await interaction . reply ( { content : ` Tried to submit map (id: ${ id } ) that already exists! ` , ephemeral : true } ) ;
return ;
}
s += ` ${ rid } , ${ rtimestamp } \n ` ;
}
const unix = Math . round ( + new Date ( ) / 1000 ) ;
s += ` ${ id } , ${ unix } \n ` ;
fs . writeFileSync ( fname , s ) ;
await interaction . reply ( ` Map (id: ${ id } ) successfully submitted. ` ) ;
}
module . exports = {
data : new SlashCommandBuilder ( )
. setName ( 'submit' )
. setDescription ( 'Submit your map' )
. addStringOption ( option =>
option . setName ( "game" )
. setDescription ( "Select the maptest game" )
. setRequired ( true )
2023-03-19 02:21:59 +00:00
. addChoices ( ... commands ) )
2022-05-13 17:01:16 +00:00
. addIntegerOption ( option =>
option . setName ( "asset_id" )
. setDescription ( "The asset ID of the model" )
. setRequired ( true ) )
,
execute
2024-04-15 08:13:32 +00:00
} ;