still so many changes needed dont fuck with anything

This commit is contained in:
nolan 2021-08-17 00:15:20 -07:00
parent 5ff8e1105a
commit 9ef265a296
21 changed files with 181 additions and 93 deletions

View File

@ -2,11 +2,17 @@
"discord": { "discord": {
"prefix": "]", "prefix": "]",
"developer": "132620781791346688", "developer": "132620781791346688",
"clientId": "697791541690892369",
"clientOptions": { "clientOptions": {
}, },
"shardOptions": { "shardOptions": {
"totalShards": "auto" "totalShards": "auto"
},
"slashCommands": {
"developerGuilds": [
"264527028751958016"
]
} }
}, },
"logger": { "logger": {

View File

@ -0,0 +1,7 @@
{
"ApplicationCommandTypes": {
"CHAT_INPUT": 1,
"USER": 2,
"MESSAGE": 3
}
}

View File

@ -1,3 +1,4 @@
module.exports = { module.exports = {
Commands: require('./Commands.json'),
Emojis: require('./Emojis.json') Emojis: require('./Emojis.json')
}; };

View File

@ -28,10 +28,18 @@ class BaseClient extends EventEmitter {
await this.shardingManager.spawn(); await this.shardingManager.spawn();
await this.slashCommandManager.global([
{
name: 'ping',
description: "a required description"
}
]);
} }
_handleMessage(shard, message) { _handleMessage(shard, message) {
if(message._logger) return this.logger._handleMessage(shard, message); if(message._logger) return this.logger._handleMessage(shard, message);
if(message._commands) return this.slashCommandManager._handleMessage(message);
} }
} }

View File

@ -1,5 +1,5 @@
const { REST } = require('@discordjs/rest'); const { REST } = require('@discordjs/rest');
// const { Routes } = require('discord-api-types/v9'); const { Routes } = require('discord-api-types/v9');
class SlashCommandManager { class SlashCommandManager {
@ -12,6 +12,57 @@ class SlashCommandManager {
} }
async _handleMessage(message) {
if(message.type === 'global') {
await this.global(message.commands);
} else if(message.type === 'guild') {
await this.guild(message.commands, { guilds: message.guilds });
}
}
async guild(commands, { guilds = [] }) {
if(!guilds.length) guilds = this.client._options.discord.slashCommands.developerGuilds;
const promises = [];
for(const guild of guilds) {
promises.push(this.rest.put(
Routes.applicationGuildCommands(this.client._options.discord.clientId, guild),
{ body: commands }
));
}
let result = null;
try {
result = await Promise.all(promises);
} catch(error) {
this.client.logger.write('error', `An issue has occured while updating guild commands. Guild command refresh aborted.\n${error.stack || error}`);
}
if(!result) return null;
this.client.logger.write('debug', `Refreshed guild slash commands for guild${guilds.length === 1 ? '' : 's'}: ${guilds.join(' ')}`);
return result;
}
async global(commands) {
// try {
// this.client.logger.write('debug', 'Starting global refresh for slash commands.');
// await this.rest.put(
// Routes.applicationGuildCommands(this.client._options.discord.clientId, "264527028751958016"),
// { body: [] }
// );
// this.client.logger.write('debug', 'Finished global refresh for slash commands.');
// } catch(error) {
// this.client.logger.write('error', 'Failed to refresh slash commands globally.');
// this.client.logger.write('error', error?.stack);
// }
}
} }
module.exports = SlashCommandManager; module.exports = SlashCommandManager;

View File

@ -1,6 +1,6 @@
const { Client, Intents } = require('discord.js'); const { Client, Intents } = require('discord.js');
const { Logger, EventHooker, Registry, Dispatcher, Resolver } = require('./client/'); const { Logger, Intercom, EventHooker, Registry, Dispatcher, Resolver } = require('./client/');
const { Observer, Command } = require('./interfaces/'); const { Observer, Command } = require('./interfaces/');
const options = require('../../options.json'); const options = require('../../options.json');
@ -16,6 +16,7 @@ class DiscordClient extends Client {
}); });
this.eventHooker = new EventHooker(this); this.eventHooker = new EventHooker(this);
this.intercom = new Intercom(this);
this.logger = new Logger(this); this.logger = new Logger(this);
this.registry = new Registry(this); this.registry = new Registry(this);
@ -44,11 +45,17 @@ class DiscordClient extends Client {
await super.login(process.env.DISCORD_TOKEN); await super.login(process.env.DISCORD_TOKEN);
this.emit('built');
this._built = true; this._built = true;
return this; return this;
} }
get singleton() {
return Boolean(this.shard.ids[0] === 0);
}
} }
module.exports = DiscordClient; module.exports = DiscordClient;

View File

@ -26,7 +26,7 @@ class Dispatcher {
async dispatch() { async dispatch() {
const observers = this.client.registry.components const observers = this.client.registry.components
.filter((c) => c.type === 'observer' && !c.disabled) .filter((c) => c._type === 'observer' && !c.disabled)
.sort((a, b) => a.priority - b.priority); .sort((a, b) => a.priority - b.priority);
this.client.logger.debug(`Starting dispatch on ${observers.size} observers.`); this.client.logger.debug(`Starting dispatch on ${observers.size} observers.`);

View File

@ -0,0 +1,35 @@
class Intercom {
constructor(client) {
this.client = client;
if(client.singleton) {
this.client.eventHooker.hook('built', () => {
this._transportCommands();
});
}
}
send(type, message = {}) {
if(typeof message !== 'object') return false;
return process.send({
[`_${type}`]: true,
...message
});
}
_transportCommands() {
const commands = this.client.registry.components
.filter((c) => c._type === 'command' && c.slash)
.map((c) => c.json);
this.send('commands', { type: 'guild', commands });
}
}
module.exports = Intercom;

View File

@ -56,7 +56,7 @@ class Logger {
} }
async transport(message = 'N/A', opts = {}) { async transport(message = 'N/A', opts = {}) {
process.send({ _logger: true, message, ...opts }); return this.client.intercom.send('logger', { message, ...opts });
} }
/* Quick & Dirty Functions */ /* Quick & Dirty Functions */

View File

@ -11,7 +11,7 @@ class Resolver {
const string = str.toLowerCase(); const string = str.toLowerCase();
const components = this.client.registry.components const components = this.client.registry.components
.filter((c) => type === 'any' ? ['command', 'setting'].includes(c.type) : c.type === type) .filter((c) => type === 'any' ? ['command', 'setting'].includes(c._type) : c._type === type)
.filter(exact ? filterExact(string) : filterInexact(string)); //eslint-disable-line no-use-before-define .filter(exact ? filterExact(string) : filterInexact(string)); //eslint-disable-line no-use-before-define
return components.size > 0 ? components.values() : []; return components.size > 0 ? components.values() : [];

View File

@ -1,5 +1,6 @@
module.exports = { module.exports = {
EventHooker: require('./EventHooker.js'), EventHooker: require('./EventHooker.js'),
Intercom: require('./Intercom.js'),
Logger: require('./Logger.js'), Logger: require('./Logger.js'),
Dispatcher: require('./Dispatcher.js'), Dispatcher: require('./Dispatcher.js'),
Registry: require('./Registry.js'), Registry: require('./Registry.js'),

View File

@ -1,10 +1,11 @@
const { Command } = require('../../../interfaces/'); const { SlashCommand } = require('../../../interfaces/');
class MuteCommand extends Command { class MuteCommand extends SlashCommand {
constructor(client) { constructor(client) {
super(client, { super(client, {
name: 'mute', name: 'mute',
description: "Silence people.",
module: 'moderation', module: 'moderation',
arguments: [ arguments: [
] ]

View File

@ -42,12 +42,14 @@ class CommandHandler extends Observer {
async interactionCreate(interaction) { async interactionCreate(interaction) {
if(!interaction.isCommand()) return undefined; if(!interaction.isCommand()) return undefined;
if(!this.client._built // if(!this.client._built
|| message.guild && !message.guild.available) return undefined; // || message.guild && !message.guild.available) return undefined;
const command = this._matchCommand(interaction.commandName); const command = this._matchCommand(interaction.commandName);
if(!command) return await interaction.reply('Command is not synced with client instance.'); console.log(interaction.commandName)
if(!command) return interaction.reply('Command is not synced with client instance.');
interaction.reply(command.resolveable);
} }
@ -76,7 +78,7 @@ class CommandHandler extends Observer {
} }
_matchCommand(message, commandName) { _matchCommand(commandName) {
const [ command ] = this.client.resolver.components(commandName, 'command', true); const [ command ] = this.client.resolver.components(commandName, 'command', true);
if(!command) return null; if(!command) return null;
@ -85,59 +87,6 @@ class CommandHandler extends Observer {
} }
async _parseArguments(message, command, parameters) {
// const arguments = this._combineArguments(command);
let word = null,
inQuotes = false;
for(const char of parameters.split('')) {
}
}
_combineArguments(command) {
if(command._combinedArguments) return command._combinedArguments;
command._combinedArguments = {
shortFlags: {},
longFlags: {},
verbals: {}
}
const combined = command._combinedArguments;
for(const argument of command.arguments) {
if(argument.types.includes('FLAG')) {
//Handle one-argument flags.
let shortFlag = argument.key.slice(1);
const shortValues = Object.values(combined.shortFlags);
if(shortValues.includes(shortFlag)) {
shortFlag = shortFlag.toUpperCase();
if(shortValues.includes(shortFlag)) {
this.client.logger.warn(`Command "${command.resolveable}" has more than two arguments starting with the letter "${shortFlag}". Argument "${argument.key}" shortflag is being skipped.`)
continue;
}
}
combined.shortFlags[shortFlag] = argument.key;
//Handle multi-argument flags.
combined.longFlags[argument.key] = argument.key;
for(const alias of argument.aliases) combined.longFlags[alias] = argument.key;
}
if(argument.types.includes('VERBAL')) {
combined.verbals[argument.key] = argument.key;
for(const alias of argument.aliases) combined.verbals[alias] = argument.key;
}
}
return combined;
}
} }
module.exports = CommandHandler; module.exports = CommandHandler;

View File

@ -1,9 +1,4 @@
const Constants = { const Constants = {
ArgumentTypes: [
"FLAG",
"VERBAL",
"SLASH"
],
ArgumentOptionTypes: { //https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-option-type ArgumentOptionTypes: { //https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-option-type
"SUB_COMMAND": 1, "SUB_COMMAND": 1,
"SUB_COMMAND_GROUP": 2, "SUB_COMMAND_GROUP": 2,

View File

@ -7,7 +7,7 @@ class Command extends Component {
super(client, { super(client, {
id: options.name, id: options.name,
type: 'command', _type: 'command',
disabled: options.disabled, disabled: options.disabled,
guarded: options.guarded guarded: options.guarded
}); });
@ -16,31 +16,17 @@ class Command extends Component {
this.name = options.name; this.name = options.name;
this.module = options.module; this.module = options.module;
this.aliases = options.aliases || [];
this.description = ""; //Localization Entry
this.usage = options.usage || null;
this.examples = options.examples || [];
this.description = options.description || "";
this.tags = options.tags || []; this.tags = options.tags || [];
this.slash = Boolean(options.slash); this.restricted = Boolean(options?.restricted);
this.restricted = Boolean(options.restricted); // this.showUsage = Boolean(options.showUsage);
this.showUsage = Boolean(options.showUsage); this.guildOnly = Boolean(options?.guildOnly);
this.guildOnly = Boolean(options.guildOnly);
this.archivable = options.archivable === undefined ? true : Boolean(options.archivable); this.archivable = options.archivable === undefined ? true : Boolean(options.archivable);
this.arguments = options.arguments || []; this.slash = Boolean(options?.slash);
this.clientPermissions = options.clientPermissions || [];
this.memberPermissions = options.memberPermissions || [];
this.throttling = options.throttling || {
usages: 5,
duration: 10
};
this._throttles = new Map();
this._invokes = { this._invokes = {
success: 0, success: 0,
fail: 0 fail: 0

View File

@ -4,7 +4,7 @@ class Component {
if(!options) return null; if(!options) return null;
this.id = options.id; //Name of the component this.id = options.id; //Name of the component
this.type = options.type; //Type of component (command, observer, etc.) this._type = options._type; //Type of component (command, observer, etc.)
this.module = options.module || null; //Group/module the component belongs to. this.module = options.module || null; //Group/module the component belongs to.
@ -77,7 +77,7 @@ class Component {
get resolveable() { get resolveable() {
return `${this.type}:${this.id}`; return `${this._type}:${this.id}`;
} }
} }

View File

@ -9,7 +9,7 @@ class Module extends Component {
super(manager, { super(manager, {
id: opts.name, id: opts.name,
type: 'module' _type: 'module'
}); });
this.manager = manager; this.manager = manager;

View File

@ -7,7 +7,7 @@ class Observer extends Component {
super(client, { super(client, {
id: options.name, id: options.name,
type: 'observer', _type: 'observer',
guarded: options.guarded, guarded: options.guarded,
disabled: options.disabled disabled: options.disabled
}); });

View File

@ -0,0 +1,40 @@
const Command = require('./Command.js');
const { Commands: CommandsConstant } = require('../../constants/');
class SlashCommand extends Command {
constructor(client, options = {}) {
if(!options) return null;
super(client, {
name: options.name,
module: options.module,
description: options.description,
tags: options.tags,
restricted: options.restricted,
guildOnly: options.guildOnly,
archivable: options.archivable,
disabled: options.disabled,
guarded: options.guarded,
slash: true
});
this.type = Object.keys(CommandsConstant.ApplicationCommandTypes).includes(options.type) ? options.type : 'CHAT_INPUT';
this.options = options.options || [];
this.defaultPermission = options.defaultPermission || {};
}
get json() {
return {
name: this.name,
description: this.description,
type: CommandsConstant.ApplicationCommandTypes[this.type],
options: this.options,
defaultPermission: this.defaultPermission
};
}
}
module.exports = SlashCommand;

View File

@ -2,6 +2,7 @@ module.exports = {
Component: require('./Component.js'), Component: require('./Component.js'),
Observer: require('./Observer.js'), Observer: require('./Observer.js'),
Module: require('./Module.js'), Module: require('./Module.js'),
SlashCommand: require('./SlashCommand.js'),
Command: require('./Command.js'), Command: require('./Command.js'),
Thing: require('./Thing.js') Thing: require('./Thing.js')
}; };