refactor: break relevant commands into files

This commit is contained in:
ethanf 2024-03-26 23:38:49 -05:00
parent df85f29f73
commit 2bed3c07e9
7 changed files with 239 additions and 309 deletions

25
commands/clear.js Normal file
View File

@ -0,0 +1,25 @@
import { SlashCommandBuilder } from "discord.js";
import { client } from "..";
import { RUNNER_ROLE_ID } from "../config.json";
const data = new SlashCommandBuilder()
.setName("clear")
.setDescription("Clears bot messages in this channel");
const permissions = [RUNNER_ROLE_ID];
const execute = async (interaction) => {
await interaction.reply("Clearing messages...");
interaction.channel.messages
.fetch({ limit: 250 })
.then((messages) => {
messages.forEach((message) => {
if (message.author.id === client.user.id) {
message.delete();
}
});
})
.catch(console.error);
};
export { data, permissions, execute };

71
commands/end.js Normal file
View File

@ -0,0 +1,71 @@
import { SlashCommandBuilder } from "discord.js";
import { findChannelfromCache } from "../utils.js";
import { RUNNER_ROLE_ID, PICKING_ID, BLU_ID, RED_ID } from "../config.json";
const data = new SlashCommandBuilder()
.setName("end")
.setDescription("Moves the team channel members back to the picking channel");
const permissions = [RUNNER_ROLE_ID];
const execute = async (interaction) => {
await interaction.reply("Moving members...");
// get voice channels
const picking = findChannelfromCache(
interaction.guild.channels.cache,
"picking",
PICKING_ID
);
const blu = findChannelfromCache(
interaction.guild.channels.cache,
"blu",
BLU_ID
);
const red = findChannelfromCache(
interaction.guild.channels.cache,
"red",
RED_ID
);
if (!picking || !blu || !red) {
return console.error("Could not find all channels for /end");
}
// get members in voice channel
let members = blu.members.concat(red.members);
if (members.size === 0) {
return await interaction.followUp("Found no members in blu or red");
}
let eCount = 0;
// move members to picking
const moveToPicking = async (member) => {
try {
await member.voice.setChannel(picking);
} catch (error) {
console.error(error);
eCount++;
}
};
const moveAllToPicking = async () => {
return Promise.all(
Array.from(members, async ([memberId, member]) => {
await moveToPicking(member);
})
);
};
moveAllToPicking().then(() =>
interaction.followUp(
`Moved members in blu and red${
eCount > 0 ? ` (error moving ${eCount} members)` : ""
}`
)
);
};
const synonyms = ["resetteams"];
export { data, permissions, execute, synonyms };

66
commands/fklist.js Normal file
View File

@ -0,0 +1,66 @@
import { SlashCommandBuilder } from "discord.js";
import { findChannelfromCache, findPlayer, getApplicableName } from "../utils";
import { RUNNER_ROLE_ID, PICKING_ID, FK_ID } from "../config.json";
// not really used since fks are now determined randomly
const data = new SlashCommandBuilder()
.setName("fklist")
.setDescription("Pulls addup channel members into fk channel and lists them");
const permissions = [RUNNER_ROLE_ID];
const synonyms = ["listfk"];
const execute = async (interaction) => {
await interaction.reply("Moving fatkids...");
// get voice channels
const picking = findChannelfromCache(
interaction.guild.channels.cache,
"picking",
PICKING_ID
);
const fk = findChannelfromCache(
interaction.guild.channels.cache,
"fatkid",
FK_ID
);
if (!picking || !fk) {
return console.error("Could not find all channels for /fklist");
}
// get members in voice channel
const members = picking.members;
if (members.size === 0) {
return await interaction.followUp("Found no members in picking");
}
let names = [],
eCount = 0;
const logFk = async (member) => {
try {
await member.voice.setChannel(fk);
names.push(getApplicableName(member));
} catch (error) {
console.error(error);
eCount++;
}
};
const logAllFks = async () => {
return Promise.all(
Array.from(members, async ([memberId, member]) => {
await logFk(member);
})
);
};
logAllFks().then(() =>
interaction.followUp(
`Fatkids: ${names.join(', ')}${eCount > 0 ? ` (error moving ${eCount} members)` : ""}`
)
);
};
export { data, permissions, execute, synonyms };

14
commands/hello.js Normal file
View File

@ -0,0 +1,14 @@
import { SlashCommandBuilder } from "discord.js";
import { RUNNER_ROLE_ID } from "../config.json";
const data = new SlashCommandBuilder()
.setName("hello")
.setDescription("Replies 'world'");
const permissions = [RUNNER_ROLE_ID];
const execute = async (interaction) => {
await interaction.reply("world");
}
export { data, permissions, execute };

238
index.js
View File

@ -1,6 +1,7 @@
import fs from "fs";
import path, { parse } from "path";
import path from "path";
import { Client, Collection, GatewayIntentBits, Partials } from "discord.js";
import { getApplicableName, findPlayer } from "./utils.js";
const {
TOKEN,
GUILD_ID,
@ -15,7 +16,7 @@ const {
let whitelistStr = require("./config.json").RANKING_WHITELIST;
const client = new Client({
export const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMembers,
@ -36,6 +37,11 @@ for (const file of commandFiles) {
const command = require(`./commands/${file}`);
if ("data" in command && "execute" in command) {
client.fileCommands.set(command.data.name, command);
if (command.synonyms) {
for (const synonym of command.synonyms) {
client.fileCommands.set(synonym, command);
}
}
} else {
console.error(`${__filename}: Invalid command file: ${file}`);
}
@ -44,43 +50,6 @@ for (const file of commandFiles) {
const backticks = "```";
const rankingsPath = path.join(__dirname, "rankings.json");
const matchString = (str, search) => {
if (!str || !search) return false;
return str.toLowerCase().includes(search.toLowerCase());
};
const findPlayer = (guild, searchName) => {
// search display name
let player = guild.members.cache.find((member) =>
matchString(member.displayName, searchName)
);
if (!player) {
// search global name
player = guild.members.cache.find((member) =>
matchString(member.user.globalName, searchName)
);
}
if (!player) {
// search username
player = guild.members.cache.find((member) =>
matchString(member.user.username, searchName)
);
}
if (!player) {
// match id
player = guild.members.cache.find((member) => member.id === searchName);
}
return player;
};
const getApplicableName = (player) => {
return (
player.displayName ||
player.user.globalName ||
player.user.username ||
player.id
);
};
const avgDiff = (arr) => {
// average absolute difference between all pairs of rank properties in a given array
@ -230,7 +199,7 @@ client.on("error", (error) => {
if (!channel) return console.error("Can't find command channel");
client.channels.cache
.get(COMMAND_CHANNEL_ID)
.send("Internal error")
.send(`Internal error: ${error.message}`)
.catch(console.error);
});
@ -244,7 +213,7 @@ client.on("interactionCreate", async (interaction) => {
if (fileCommand.permissions) {
const member = interaction.member;
for (const permission of fileCommand.permissions) {
if (!member.roles.cache.has(permission)) {
if (!member.roles.cache.has(permission) && member.id !== DEBUG_ADMIN_ID) {
await interaction.reply({
content: "You lack the required permissions",
ephemeral: true,
@ -271,177 +240,6 @@ client.on("interactionCreate", async (interaction) => {
return;
}
if (
command === "scout" ||
command === "soldier" ||
command === "pyro" ||
command === "demoman" ||
command === "demo" ||
command === "heavy" ||
command === "engineer" ||
command === "engi" ||
command === "medic" ||
command === "sniper" ||
command === "spy"
) {
// get voice channels
const picking = interaction.guild.channels.cache.find(
(channel) => channel.name === "picking" || channel.id === PICKING_ID
);
if (!picking) return console.error("Can't find channel 'picking'!");
const captain = interaction.guild.channels.cache.find(
(channel) => channel.name === "captains" || channel.id === CAPTAIN_ID
);
if (!captain) return console.error("Can't find channel 'captains'!");
// make sure user is in picking or captain channel
if (
!picking.members.has(interaction.user.id) &&
!captain.members.has(interaction.user.id)
) {
await interaction.reply({
content: "Must be in picking or captains channel to use this command",
ephemeral: true,
});
return;
} else {
await interaction.reply({
content: "Checking picking channel...",
ephemeral: true,
});
// set role name
let roleName = command;
if (command === "demoman") roleName = "demo";
if (command === "engi") roleName = "engineer";
// check each member in picking channel for role
let str = `In picking (${roleName}):`;
for (const member of picking.members.values()) {
if (member.roles.cache.find((role) => role.name === roleName)) {
if (str !== `In picking (${roleName}):`) str += ",";
str += " " + getApplicableName(member);
}
}
if (str === `In picking (${roleName}):`)
str = `None found ¯\\_(ツ)_/¯ (${roleName})`;
// respond
return await interaction.followUp(str);
}
}
if (command === "hello") {
await interaction.reply("world");
}
if (
command === "topicking" ||
command === "end" ||
command === "resetteams"
) {
await interaction.reply("Moving members...");
// get voice channels
const blu = interaction.guild.channels.cache.find(
(channel) => channel.name === "blu" || channel.id === BLU_ID
);
if (!blu) return console.error("Can't find channel 'blu'!");
const red = interaction.guild.channels.cache.find(
(channel) => channel.name === "red" || channel.id === RED_ID
);
if (!red) return console.error("Can't find channel 'red'!");
const picking = interaction.guild.channels.cache.find(
(channel) => channel.name === "picking" || channel.id === PICKING_ID
);
if (!picking) return console.error("Can't find channel 'picking'!");
// get members in voice channel
let members = blu.members.concat(red.members);
if (members.size === 0) {
return await interaction.followUp("Found no members in blu or red");
}
let eCount = 0;
// move members to picking
const moveToPicking = async (member) => {
try {
await member.voice.setChannel(picking);
} catch (error) {
console.error(error);
eCount++;
}
};
const moveAllToPicking = async () => {
return Promise.all(
Array.from(members, async ([memberId, member]) => {
await moveToPicking(member);
})
);
};
moveAllToPicking().then(() =>
interaction.followUp(
`Moved members in blu and red${
eCount > 0 ? ` (error moving ${eCount} members)` : ""
}`
)
);
}
if (command === "fklist" || command === "listfk") {
// moves players in picking to fatkid channel, for use in captain pugs
await interaction.reply("Moving fatkids...");
// get voice channels
const picking = interaction.guild.channels.cache.find(
(channel) => channel.name === "picking" || channel.id === PICKING_ID
);
if (!picking) return console.error("Can't find channel 'add-up'!");
const fk = interaction.guild.channels.cache.find(
(channel) => channel.name === "fatkid" || channel.id === FK_ID
);
if (!fk) return console.error("Can't find channel 'fatkid'!");
// get members in voice channel
const members = picking.members;
if (members.size === 0) {
return await interaction.followUp("Found no members in picking");
}
let str = "",
eCount = 0;
const logFk = async (member) => {
try {
await member.voice.setChannel(fk);
if (str.length > 0) str += ", ";
str += getApplicableName(member);
} catch (error) {
console.error(error);
eCount++;
}
};
const logAllFks = async () => {
return Promise.all(
Array.from(members, async ([memberId, member]) => {
await logFk(member);
})
);
};
logAllFks().then(() =>
interaction.followUp(
`Fatkids: ${str}${
eCount > 0 ? ` (error moving ${eCount} members)` : ""
}`
)
);
}
if (command === "pick" || command === "autocaptain") {
await interaction.reply("Picking teams...");
@ -608,22 +406,6 @@ client.on("interactionCreate", async (interaction) => {
}`
);
}
if (command === "clear" || command === "bclear") {
await interaction.reply("Clearing messages...");
let channel = client.channels.cache.get(COMMAND_CHANNEL_ID);
if (!channel) return console.error("Can't find command channel");
channel.messages
.fetch({ limit: 100 })
.then((messages) => {
messages.forEach((message) => {
if (message.author.id === client.user.id) {
message.delete();
}
});
})
.catch(console.error);
}
});
/*

View File

@ -5,86 +5,6 @@ const path = require("path");
// set static commands
const commands = [
{
name: "hello",
description: "Replies 'world'",
},
{
name: "topicking",
description: "Pulls team and addup channel members into picking channel",
},
{
name: "end",
description: "Pulls team and addup channel members into picking channel",
},
{
name: "resetteams",
description: "Pulls team channel members into picking channel",
},
/*{
name: "testfk",
description: "debug fk",
},*/
{
name: "fklist",
description: "Pulls addup channel members into fk channel and lists them",
},
{
name: "listfk",
description: "Pulls addup channel members into fk channel and lists them",
},
{
name: "clear",
description: "Clears bot messages in command channel",
},
{
name: "bclear",
description: "Clears bot messages in command channel",
},
{
name: "scout",
description: "Lists picking channel members with scout role",
},
{
name: "soldier",
description: "Lists picking channel members with soldier role",
},
{
name: "pyro",
description: "Lists picking channel members with pyro role",
},
{
name: "demo",
description: "Lists picking channel members with demo role",
},
{
name: "demoman",
description: "Alias of /demo",
},
{
name: "heavy",
description: "Lists picking channel members with heavy role",
},
{
name: "engineer",
description: "Lists picking channel members with engineer role",
},
{
name: "engi",
description: "Alias of /engineer",
},
{
name: "medic",
description: "Lists picking channel members with medic role",
},
{
name: "sniper",
description: "Lists picking channel members with sniper role",
},
{
name: "spy",
description: "Lists picking channel members with spy role",
},
{
name: "pick",
description: "Automatically picks teams",
@ -102,7 +22,16 @@ const commandFiles = fs.readdirSync(commandsPath);
for (const file of commandFiles) {
const command = require(`./commands/${file}`);
if ("data" in command && "execute" in command) {
commands.push(command.data.toJSON());
let commandData = command.data;
commands.push(commandData);
if (command.synonyms) {
for (const synonym of command.synonyms) {
commands.push({
...commandData,
name: synonym,
});
}
}
} else {
console.error(`${__filename}: Invalid command file: ${file}`);
}

43
utils.js Normal file
View File

@ -0,0 +1,43 @@
export const findChannelfromCache = (channelCache, name, id) => {
return channelCache.find(
(channel) => channel.name === name || channel.id === id
);
}
export const matchString = (str, search) => {
if (!str || !search) return false;
return str.toLowerCase().includes(search.toLowerCase());
};
export const findPlayer = (guild, searchName) => {
// search display name
let player = guild.members.cache.find((member) =>
matchString(member.displayName, searchName)
);
if (!player) {
// search global name
player = guild.members.cache.find((member) =>
matchString(member.user.globalName, searchName)
);
}
if (!player) {
// search username
player = guild.members.cache.find((member) =>
matchString(member.user.username, searchName)
);
}
if (!player) {
// match id
player = guild.members.cache.find((member) => member.id === searchName);
}
return player;
};
export const getApplicableName = (player) => {
return (
player.displayName ||
player.user.globalName ||
player.user.username ||
player.id
);
};