2020-07-25 11:01:24 +00:00
import Event from "../core/event" ;
import Command from "../core/command" ;
import $ from "../core/lib" ;
import { Message , Permissions , Collection } from "discord.js" ;
import { Config , Storage } from "../core/structures" ;
2020-07-25 23:32:49 +00:00
import { loadCommands } from "../core/command" ;
2020-07-25 11:01:24 +00:00
// It's a rather hacky solution, but since there's no top-level await, I just have to make the loading conditional.
let commands : Collection < string , Command > | null = null ;
export default new Event ( {
async on ( message : Message )
{
// Load commands if it hasn't already done so. Luckily, it's called once at most.
if ( ! commands )
2020-07-25 23:32:49 +00:00
commands = await loadCommands ( ) ;
2020-07-25 11:01:24 +00:00
// Message Setup //
if ( message . author . bot )
return ;
const prefix = Storage . getGuild ( message . guild ? . id || "N/A" ) . prefix || Config . prefix ;
if ( ! message . content . startsWith ( prefix ) )
return ;
const [ header , . . . args ] = message . content . substring ( prefix . length ) . split ( / +/ ) ;
if ( ! commands . has ( header ) )
return ;
if ( message . channel . type === "text" && ! message . channel . permissionsFor ( message . client . user || "" ) ? . has ( Permissions . FLAGS . SEND_MESSAGES ) )
{
let status ;
if ( message . member ? . hasPermission ( Permissions . FLAGS . ADMINISTRATOR ) )
status = "Because you're a server admin, you have the ability to change that channel's permissions to match if that's what you intended." ;
else
status = "Try using a different channel or contacting a server admin to change permissions of that channel if you think something's wrong." ;
return message . author . send ( ` I don't have permission to send messages in ${ message . channel . toString ( ) } . ${ status } ` ) ;
}
$ . log ( ` ${ message . author . username } # ${ message . author . discriminator } executed the command " ${ header } " with arguments " ${ args } ". ` ) ;
// Subcommand Recursion //
let command = commands . get ( header ) ;
if ( ! command ) return $ . warn ( ` Command " ${ header } " was called but for some reason it's still undefined! ` ) ;
const params : any [ ] = [ ] ;
let isEndpoint = false ;
for ( let param of args )
{
if ( command . endpoint )
{
if ( command . subcommands || command . user || command . number || command . any )
$ . warn ( ` An endpoint cannot have subcommands! Check ${ prefix } ${ header } again. ` ) ;
isEndpoint = true ;
break ;
}
2020-07-26 02:35:53 +00:00
const type = command . resolve ( param ) ;
command = command . get ( param ) ;
if ( type === Command . TYPES . USER )
2020-07-25 11:01:24 +00:00
{
const id = param . match ( /\d+/g ) ! [ 0 ] ;
try { params . push ( await message . client . users . fetch ( id ) ) }
catch ( error ) { return message . channel . send ( ` No user found by the ID \` ${ id } \` ! ` ) }
}
2020-07-26 02:35:53 +00:00
else if ( type === Command . TYPES . NUMBER )
2020-07-25 11:01:24 +00:00
params . push ( Number ( param ) ) ;
2020-07-26 02:35:53 +00:00
else if ( type !== Command . TYPES . SUBCOMMAND )
2020-07-25 11:01:24 +00:00
params . push ( param ) ;
}
if ( isEndpoint )
return message . channel . send ( "Too many arguments!" ) ;
// Execute with dynamic library attached. //
// The purpose of using $.bind($) is to clone the function so as to not modify the original $.
// The cloned function doesn't copy the properties, so Object.assign() is used.
// Object.assign() modifies the first element and returns that, the second element applies its properties and the third element applies its own overriding the second one.
command . execute ( Object . assign ( $ . bind ( $ ) , {
args : params ,
author : message.author ,
channel : message.channel ,
client : message.client ,
guild : message.guild ,
member : message.member ,
message : message
} , $ ) ) ;
}
} ) ;