From bec15645df9d7bb35aac8336f0f92224d96503a3 Mon Sep 17 00:00:00 2001 From: Jacob Date: Tue, 8 Oct 2024 16:25:52 +1100 Subject: [PATCH 1/8] boo --- src/minecraft/commands/booCommand.js | 63 ++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 src/minecraft/commands/booCommand.js diff --git a/src/minecraft/commands/booCommand.js b/src/minecraft/commands/booCommand.js new file mode 100644 index 00000000..b706d6b9 --- /dev/null +++ b/src/minecraft/commands/booCommand.js @@ -0,0 +1,63 @@ +const minecraftCommand = require("../../contracts/minecraftCommand.js"); +const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); +const helperFunctions = require("../../contracts/helperFunctions.js"); + +class BooCommand extends minecraftCommand { + constructor(minecraft) { + super(minecraft); + + this.name = "boo"; + this.aliases = []; + this.description = "Boo someone!"; + this.options = [ + { + name: "username", + description: "User you want to boo!", + required: true, + }, + ]; + this.isOnCooldown = false; + } + + async onCommand(username, message) { + try { + if (this.getArgs(message).length === 0) { + // eslint-disable-next-line no-throw-literal + throw "You must provide a user to boo!"; + } + + if (9 !== new Date().getMonth()) { + // eslint-disable-next-line no-throw-literal + throw "It's not October!"; + } + + if (this.isOnCooldown) { + return this.send(`/gc ${this.name} Command is on cooldown`); + } + + this.send(`/boo ${this.getArgs(message)[0]}`); + await delay(690); + this.send(`/msg ${this.getArgs(message)[0]} ${username} Booed You!`); + await delay(690); + this.send(`/gc Booed ${this.getArgs(message)[0]}!`); + this.isOnCooldown = true; + // CREDITS: @jaxieflaxie for finding this cooldown reset + setTimeout(() => { + bot.chat( + `/w ${ + bot.username + } jaxieflaxie is the best wristspasm member! your cool if u see this - ${helperFunctions.generateID(24)}`, + ); + setTimeout(() => { + bot.chat(`/w ${bot.username} ${helperFunctions.generateID(48)}`); + this.isOnCooldown = false; + }, 30000); + }, 30000); + this.isOnCooldown = false; + } catch (error) { + this.send(`/gc [ERROR] ${error}`); + } + } +} + +module.exports = BooCommand; From 06ad207b060f886be2fa322ead0c8a289ee08aaa Mon Sep 17 00:00:00 2001 From: Jacob <55346310+Kathund@users.noreply.github.com> Date: Sat, 26 Oct 2024 23:23:02 +0800 Subject: [PATCH 2/8] Garden Command (#286) --- API/constants/xp_tables.js | 72 +++++++++++++++++++++++++ API/functions/getGarden.js | 21 ++++++++ API/functions/getLatestProfile.js | 4 +- API/stats/garden.js | 19 +++++++ src/minecraft/commands/gardenCommand.js | 40 ++++++++++++++ src/minecraft/commands/jacobCommand.js | 2 +- 6 files changed, 156 insertions(+), 2 deletions(-) create mode 100644 API/functions/getGarden.js create mode 100644 API/stats/garden.js create mode 100644 src/minecraft/commands/gardenCommand.js diff --git a/API/constants/xp_tables.js b/API/constants/xp_tables.js index be538c74..9d65dc68 100644 --- a/API/constants/xp_tables.js +++ b/API/constants/xp_tables.js @@ -13,6 +13,17 @@ module.exports = { social: 25, dungeoneering: 50, hotm: 10, + gardenXp: 15, + wheat: 46, + carrot: 46, + potato: 46, + melon: 46, + pumpkin: 46, + sugarCane: 46, + cocoaBeans: 46, + cactus: 46, + mushroom: 46, + netherWart: 46, }, normal: [ 50, 125, 200, 300, 500, 750, 1000, 1500, 2000, 3500, 5000, 7500, 10000, 15000, 20000, 30000, 50000, 75000, 100000, @@ -44,4 +55,65 @@ module.exports = { blaze: [10, 30, 250, 1500, 5000, 20000, 100000, 400000, 1000000], vampire: [20, 75, 240, 840, 2400], }, + gardenXp: [0, 70, 70, 140, 240, 600, 1500, 2000, 2500, 3000, 10000, 10000, 10000, 10000, 10000], + wheat: [ + 30, 50, 80, 170, 330, 670, 1330, 2500, 3500, 5000, 6500, 8000, 10000, 20000, 35000, 50000, 75000, 100000, 175000, + 250000, 350000, 500000, 750000, 1000000, 1300000, 1600000, 2000000, 2300000, 2600000, 3000000, 3000000, 3000000, + 3000000, 3000000, 3000000, 3000000, 3000000, 3000000, 3000000, 3000000, 3000000, 3000000, 3000000, 3000000, 3000000, + 3000000, + ], + carrot: [ + 100, 150, 250, 500, 1500, 2500, 5000, 7500, 10000, 15000, 20000, 25000, 40000, 70000, 100000, 200000, 250000, + 250000, 500000, 750000, 1000000, 1500000, 2000000, 3000000, 4000000, 5000000, 6000000, 7000000, 8000000, 9000000, + 10000000, 10000000, 10000000, 10000000, 10000000, 10000000, 10000000, 10000000, 10000000, 10000000, 10000000, + 10000000, 10000000, 10000000, 10000000, 10000000, + ], + potato: [ + 100, 150, 250, 500, 1500, 2500, 5000, 7500, 10000, 15000, 20000, 25000, 40000, 70000, 100000, 200000, 250000, + 250000, 500000, 750000, 1000000, 1500000, 2000000, 3000000, 4000000, 5000000, 6000000, 7000000, 8000000, 9000000, + 10000000, 10000000, 10000000, 10000000, 10000000, 10000000, 10000000, 10000000, 10000000, 10000000, 10000000, + 10000000, 10000000, 10000000, 10000000, 10000000, + ], + melon: [ + 150, 250, 400, 850, 1650, 3350, 6650, 12500, 17500, 25000, 32500, 40000, 50000, 100000, 175000, 250000, 375000, + 500000, 875000, 1250000, 1750000, 2500000, 3750000, 5000000, 6500000, 8000000, 10000000, 11500000, 13000000, + 15000000, 15000000, 15000000, 15000000, 15000000, 15000000, 15000000, 15000000, 15000000, 15000000, 15000000, + 15000000, 15000000, 15000000, 15000000, 15000000, 15000000, + ], + pumpkin: [ + 30, 50, 80, 170, 330, 670, 1330, 2500, 3500, 5000, 6500, 8000, 10000, 20000, 35000, 50000, 75000, 100000, 175000, + 250000, 350000, 500000, 750000, 1000000, 1300000, 1600000, 2000000, 2300000, 2600000, 3000000, 3000000, 3000000, + 3000000, 3000000, 3000000, 3000000, 3000000, 3000000, 3000000, 3000000, 3000000, 3000000, 3000000, 3000000, 3000000, + 3000000, + ], + sugarCane: [ + 60, 100, 160, 340, 660, 1340, 2660, 5000, 7000, 10000, 13000, 16000, 20000, 40000, 70000, 100000, 150000, 200000, + 350000, 500000, 700000, 1000000, 1500000, 2000000, 2600000, 3200000, 4000000, 4600000, 5200000, 6000000, 6000000, + 6000000, 6000000, 6000000, 6000000, 6000000, 6000000, 6000000, 6000000, 6000000, 6000000, 6000000, 6000000, 6000000, + 6000000, 6000000, + ], + cocoaBeans: [ + 90, 150, 250, 500, 1000, 2000, 4000, 7500, 10000, 15000, 20000, 25000, 30000, 50000, 100000, 150000, 200000, 300000, + 500000, 750000, 1000000, 1500000, 2000000, 3000000, 4000000, 5000000, 6000000, 7000000, 8000000, 9000000, 9000000, + 9000000, 9000000, 9000000, 9000000, 9000000, 9000000, 9000000, 9000000, 9000000, 9000000, 9000000, 9000000, 9000000, + 9000000, 9000000, + ], + cactus: [ + 60, 100, 160, 340, 660, 1340, 2660, 5000, 7000, 10000, 13000, 16000, 20000, 40000, 70000, 100000, 150000, 200000, + 350000, 500000, 700000, 1000000, 1500000, 2000000, 2600000, 3200000, 4000000, 4600000, 5200000, 6000000, 6000000, + 6000000, 6000000, 6000000, 6000000, 6000000, 6000000, 6000000, 6000000, 6000000, 6000000, 6000000, 6000000, 6000000, + 6000000, 6000000, + ], + mushroom: [ + 30, 50, 80, 170, 330, 670, 1330, 2500, 3500, 5000, 6500, 8000, 10000, 20000, 35000, 50000, 75000, 100000, 175000, + 250000, 350000, 500000, 750000, 1000000, 1300000, 1600000, 2000000, 2300000, 2600000, 3000000, 3000000, 3000000, + 3000000, 3000000, 3000000, 3000000, 3000000, 3000000, 3000000, 3000000, 3000000, 3000000, 3000000, 3000000, 3000000, + 3000000, + ], + netherWart: [ + 90, 150, 250, 500, 1000, 2000, 4000, 7500, 10000, 15000, 20000, 25000, 30000, 50000, 100000, 150000, 200000, 300000, + 500000, 750000, 1000000, 1500000, 2000000, 3000000, 4000000, 5000000, 6000000, 7000000, 8000000, 9000000, 9000000, + 9000000, 9000000, 9000000, 9000000, 9000000, 9000000, 9000000, 9000000, 9000000, 9000000, 9000000, 9000000, 9000000, + 9000000, 9000000, + ], }; diff --git a/API/functions/getGarden.js b/API/functions/getGarden.js new file mode 100644 index 00000000..a367d8ae --- /dev/null +++ b/API/functions/getGarden.js @@ -0,0 +1,21 @@ +/* eslint-disable no-throw-literal */ +const config = require("../../config.json"); +const axios = require("axios"); + +async function getGarden(profileID, uuid) { + try { + const { data } = await axios.get( + `https://api.hypixel.net/v2/skyblock/garden?key=${config.minecraft.API.hypixelAPIkey}&profile=${profileID}`, + ); + + if (data === undefined || data.success === false) { + throw "Request to Hypixel API failed. Please try again!"; + } + + return { garden: data.garden }; + } catch (e) { + throw new Error(e); + } +} + +module.exports = { getGarden }; diff --git a/API/functions/getLatestProfile.js b/API/functions/getLatestProfile.js index 6a364277..704a0e0f 100644 --- a/API/functions/getLatestProfile.js +++ b/API/functions/getLatestProfile.js @@ -1,13 +1,14 @@ /* eslint-disable no-throw-literal */ const { getUUID } = require("../../src/contracts/API/mowojangAPI.js"); const { getMuseum } = require("./getMuseum.js"); +const { getGarden } = require("./getGarden.js"); const { isUuid } = require("../utils/uuid.js"); const config = require("../../config.json"); const axios = require("axios"); const cache = new Map(); -async function getLatestProfile(uuid, options = { museum: false }) { +async function getLatestProfile(uuid, options = { museum: false, garden: false }) { if (!isUuid(uuid)) { uuid = await getUUID(uuid).catch((error) => { throw error; @@ -59,6 +60,7 @@ async function getLatestProfile(uuid, options = { museum: false }) { playerRes: playerRes.player, uuid: uuid, ...(options.museum ? await getMuseum(profileData.profile_id, uuid) : {}), + ...(options.garden ? await getGarden(profileData.profile_id) : {}), }; cache.set(uuid, output); diff --git a/API/stats/garden.js b/API/stats/garden.js new file mode 100644 index 00000000..010c4a0c --- /dev/null +++ b/API/stats/garden.js @@ -0,0 +1,19 @@ +const calcSkill = require("../constants/skills.js"); + +module.exports = (profile) => { + return { + level: calcSkill("gardenXp", profile?.garden_experience || 0), + cropMilesstone: { + wheat: calcSkill("wheat", profile?.resources_collected?.WHEAT || 0), + carrot: calcSkill("carrot", profile?.resources_collected?.CARROT_ITEM || 0), + sugarCane: calcSkill("sugarCane", profile?.resources_collected?.SUGAR_CANE || 0), + potato: calcSkill("potato", profile?.resources_collected?.POTATO_ITEM || 0), + netherWart: calcSkill("netherWart", profile?.resources_collected?.NETHER_STALK || 0), + pumpkin: calcSkill("pumpkin", profile?.resources_collected?.PUMPKIN || 0), + melon: calcSkill("melon", profile?.resources_collected?.MELON || 0), + mushroom: calcSkill("mushroom", profile?.resources_collected?.MUSHROOM_COLLECTION || 0), + cocoaBeans: calcSkill("cocoaBeans", profile?.resources_collected?.["INK_SACK:3"] || 0), + cactus: calcSkill("cactus", profile?.resources_collected?.CACTUS || 0), + }, + }; +}; diff --git a/src/minecraft/commands/gardenCommand.js b/src/minecraft/commands/gardenCommand.js new file mode 100644 index 00000000..444a984e --- /dev/null +++ b/src/minecraft/commands/gardenCommand.js @@ -0,0 +1,40 @@ +const { getLatestProfile } = require("../../../API/functions/getLatestProfile.js"); +const { formatUsername } = require("../../contracts/helperFunctions.js"); +const minecraftCommand = require("../../contracts/minecraftCommand.js"); +const getGarden = require("../../../API/stats/garden.js"); + +class GardenCommand extends minecraftCommand { + constructor(minecraft) { + super(minecraft); + + this.name = "garden"; + this.aliases = []; + this.description = "Skyblock Garden Stats of specified user."; + this.options = [ + { + name: "username", + description: "Minecraft username", + required: false, + }, + ]; + } + + async onCommand(username, message) { + try { + // CREDITS: by @Kathund (https://github.com/Kathund) + username = this.getArgs(message)[0] || username; + + const data = await getLatestProfile(username, { garden: true }); + username = formatUsername(username, data.profileData?.game_mode); + const garden = getGarden(data.garden); + + this.send( + `/gc ${username}'s garden ${garden.level.level} | Crop Milestones: Wheat: ${garden.cropMilesstone.wheat.level} | Carrot: ${garden.cropMilesstone.carrot.level} | Cane: ${garden.cropMilesstone.sugarCane.level} | Potato: ${garden.cropMilesstone.potato.level} | Wart: ${garden.cropMilesstone.netherWart.level} | Pumpkin: ${garden.cropMilesstone.pumpkin.level} | Melon: ${garden.cropMilesstone.melon.level} | Mushroom: ${garden.cropMilesstone.mushroom.level} | Cocoa: ${garden.cropMilesstone.cocoaBeans.level} | Cactus: ${garden.cropMilesstone.cactus.level}`, + ); + } catch (error) { + this.send(`/gc [ERROR] ${error}`); + } + } +} + +module.exports = GardenCommand; diff --git a/src/minecraft/commands/jacobCommand.js b/src/minecraft/commands/jacobCommand.js index 5d8ff705..0754f3c0 100644 --- a/src/minecraft/commands/jacobCommand.js +++ b/src/minecraft/commands/jacobCommand.js @@ -9,7 +9,7 @@ class JacobCommand extends minecraftCommand { super(minecraft); this.name = "jacob"; - this.aliases = ["jacobs", "garden", "jacobcontest", "contest"]; + this.aliases = ["jacobs", "jacobcontest", "contest"]; this.description = "Jacob's Contest Stats of specified user."; this.options = []; } From 5a8101f74fbecb1c96e51cda2ba9db5c42ce9186 Mon Sep 17 00:00:00 2001 From: Jacob <55346310+Kathund@users.noreply.github.com> Date: Thu, 5 Dec 2024 01:58:22 +0800 Subject: [PATCH 3/8] Fix help (#287) * Fix /help being too long * Fix Naming on discord commands * Update /info to also have fixed commands --- src/discord/commands/blacklistCommand.js | 4 +- src/discord/commands/demoteCommand.js | 4 +- src/discord/commands/forceVerifyCommand.js | 2 +- src/discord/commands/helpCommand.js | 142 +++++++++----------- src/discord/commands/infoCommand.js | 145 +++++++++++---------- src/discord/commands/inviteCommand.js | 4 +- src/discord/commands/kickCommand.js | 4 +- src/discord/commands/linkedCommand.js | 4 +- src/discord/commands/muteCommand.js | 4 +- src/discord/commands/promoteCommand.js | 4 +- src/discord/commands/unmuteCommand.js | 4 +- src/discord/commands/verifyCommand.js | 4 +- 12 files changed, 159 insertions(+), 166 deletions(-) diff --git a/src/discord/commands/blacklistCommand.js b/src/discord/commands/blacklistCommand.js index ccae4366..32d9796c 100644 --- a/src/discord/commands/blacklistCommand.js +++ b/src/discord/commands/blacklistCommand.js @@ -24,7 +24,7 @@ module.exports = { ], }, { - name: "name", + name: "username", description: "Minecraft Username", type: 3, required: true, @@ -32,7 +32,7 @@ module.exports = { ], execute: async (interaction) => { - const name = interaction.options.getString("name"); + const name = interaction.options.getString("username"); const arg = interaction.options.getString("arg").toLowerCase(); if (arg == "add") { diff --git a/src/discord/commands/demoteCommand.js b/src/discord/commands/demoteCommand.js index f7b45fd3..adf1b206 100644 --- a/src/discord/commands/demoteCommand.js +++ b/src/discord/commands/demoteCommand.js @@ -7,7 +7,7 @@ module.exports = { requiresBot: true, options: [ { - name: "name", + name: "username", description: "Minecraft Username", type: 3, required: true, @@ -15,7 +15,7 @@ module.exports = { ], execute: async (interaction) => { - const name = interaction.options.getString("name"); + const name = interaction.options.getString("username"); bot.chat(`/g demote ${name}`); const embed = new SuccessEmbed(`Successfully demoted \`${name}\` by one guild rank.`); diff --git a/src/discord/commands/forceVerifyCommand.js b/src/discord/commands/forceVerifyCommand.js index 1b61a1e0..97d25f8b 100644 --- a/src/discord/commands/forceVerifyCommand.js +++ b/src/discord/commands/forceVerifyCommand.js @@ -13,7 +13,7 @@ module.exports = { required: true, }, { - name: "name", + name: "username", description: "Minecraft Username", type: 3, required: true, diff --git a/src/discord/commands/helpCommand.js b/src/discord/commands/helpCommand.js index 883b0504..5fe224a9 100644 --- a/src/discord/commands/helpCommand.js +++ b/src/discord/commands/helpCommand.js @@ -2,6 +2,7 @@ const HypixelDiscordChatBridgeError = require("../../contracts/errorHandler.js") const { EmbedBuilder } = require("discord.js"); const config = require("../../../config.json"); const fs = require("fs"); +const { getCommands } = require("./infoCommand.js"); module.exports = { name: "help", @@ -16,92 +17,77 @@ module.exports = { ], execute: async (interaction) => { - const commandName = interaction.options.getString("command") || undefined; + try { + const commandName = interaction.options.getString("command") || undefined; + const { discordCommands, minecraftCommands } = getCommands(interaction.client.commands); - if (commandName === undefined) { - const discordCommands = interaction.client.commands - .map(({ name, options }) => { - const optionsString = options?.map(({ name, required }) => (required ? ` (${name})` : ` [${name}]`)).join(""); - return `- \`${name}${optionsString ? optionsString : ""}\`\n`; - }) - .join(""); + if (commandName === undefined) { + const helpMenu = new EmbedBuilder() + .setColor(0x0099ff) + .setTitle("Hypixel Discord Chat Bridge Commands") + .setDescription("`()` = **required** argument, `[]` = **optional** argument\n`u` = Minecraft Username") + .addFields( + { + name: "**Minecraft**: ", + value: `${minecraftCommands}`, + inline: true, + }, + { + name: "**Discord**: ", + value: `${discordCommands}`, + inline: true, + }, + ) + .setFooter({ + text: "by @duckysolucky | /help [command] for more information", + iconURL: "https://imgur.com/tgwQJTX.png", + }); - const minecraftCommands = fs - .readdirSync("./src/minecraft/commands") - .filter((file) => file.endsWith(".js")) - .map((file) => { - const command = new (require(`../../minecraft/commands/${file}`))(); - const optionsString = command.options - ?.map(({ name, required }) => (required ? ` (${name})` : ` [${name}]`)) - .join(""); + await interaction.followUp({ embeds: [helpMenu] }); + } else { + const minecraftCommand = fs + .readdirSync("./src/minecraft/commands") + .filter((file) => file.endsWith(".js")) + .map((file) => new (require(`../../minecraft/commands/${file}`))()) + .find((command) => command.name === commandName || command.aliases.includes(commandName)); - return `- \`${command.name}${optionsString}\`\n`; - }) - .join(""); + const type = minecraftCommand ? "minecraft" : "discord"; - const helpMenu = new EmbedBuilder() - .setColor(0x0099ff) - .setTitle("Hypixel Discord Chat Bridge Commands") - .setDescription("() = required argument, [] = optional argument") - .addFields( - { - name: "**Minecraft**: ", - value: `${minecraftCommands}`, - inline: true, - }, - { - name: "**Discord**: ", - value: `${discordCommands}`, - inline: true, - }, - ) - .setFooter({ - text: "by @duckysolucky | /help [command] for more information", - iconURL: "https://imgur.com/tgwQJTX.png", - }); + const command = interaction.client.commands.find((command) => command.name === commandName) ?? minecraftCommand; + if (command === undefined) { + throw new HypixelDiscordChatBridgeError(`Command ${commandName} not found.`); + } - await interaction.followUp({ embeds: [helpMenu] }); - } else { - const minecraftCommand = fs - .readdirSync("./src/minecraft/commands") - .filter((file) => file.endsWith(".js")) - .map((file) => new (require(`../../minecraft/commands/${file}`))()) - .find((command) => command.name === commandName || command.aliases.includes(commandName)); + const description = `${ + command.aliases + ? `\nAliases: ${command.aliases + .map((aliase) => { + return `\`${config.minecraft.bot.prefix}${aliase}\``; + }) + .join(", ")}\n\n` + : "" + }${command.description}\n\n${ + command.options + ?.map(({ name, required, description }) => { + const optionString = required ? `(${name})` : `[${name}]`; + return `\`${optionString}\`: ${description}\n`; + }) + .join("") || "" + }`; - const type = minecraftCommand ? "minecraft" : "discord"; + const embed = new EmbedBuilder() + .setColor(0x0099ff) + .setTitle(`**${type === "discord" ? "/" : config.minecraft.bot.prefix}${command.name}**`) + .setDescription(description + "\n") + .setFooter({ + text: "by @duckysolucky | () = required, [] = optional", + iconURL: "https://imgur.com/tgwQJTX.png", + }); - const command = interaction.client.commands.find((command) => command.name === commandName) ?? minecraftCommand; - if (command === undefined) { - throw new HypixelDiscordChatBridgeError(`Command ${commandName} not found.`); + await interaction.followUp({ embeds: [embed] }); } - - const description = `${ - command.aliases - ? `\nAliases: ${command.aliases - .map((aliase) => { - return `\`${config.minecraft.bot.prefix}${aliase}\``; - }) - .join(", ")}\n\n` - : "" - }${command.description}\n\n${ - command.options - ?.map(({ name, required, description }) => { - const optionString = required ? `(${name})` : `[${name}]`; - return `\`${optionString}\`: ${description}\n`; - }) - .join("") || "" - }`; - - const embed = new EmbedBuilder() - .setColor(0x0099ff) - .setTitle(`**${type === "discord" ? "/" : config.minecraft.bot.prefix}${command.name}**`) - .setDescription(description + "\n") - .setFooter({ - text: "by @duckysolucky | () = required, [] = optional", - iconURL: "https://imgur.com/tgwQJTX.png", - }); - - await interaction.followUp({ embeds: [embed] }); + } catch (error) { + console.log(error); } }, }; diff --git a/src/discord/commands/infoCommand.js b/src/discord/commands/infoCommand.js index a39eab3d..07992ea6 100644 --- a/src/discord/commands/infoCommand.js +++ b/src/discord/commands/infoCommand.js @@ -1,78 +1,19 @@ const HypixelDiscordChatBridgeError = require("../../contracts/errorHandler.js"); +const { replaceVariables } = require("../../contracts/helperFunctions.js"); const { EmbedBuilder } = require("discord.js"); const config = require("../../../config.json"); const fs = require("fs"); -module.exports = { - name: "info", - description: "Shows information about the bot.", - requiresBot: true, - - execute: async (interaction) => { - if (bot === undefined || bot._client.chat === undefined) { - throw new HypixelDiscordChatBridgeError("Bot doesn't seem to be connected to Hypixel. Please try again."); - } - - const commands = interaction.client.commands; - - const { discordCommands, minecraftCommands } = getCommands(commands); - - const infoEmbed = new EmbedBuilder() - .setColor(0x0099ff) - .setTitle("Hypixel Bridge Bot Commands") - .addFields( - { - name: "**Minecraft Commands**: ", - value: `${minecraftCommands}`, - inline: true, - }, - { - name: "**Discord Commands**: ", - value: `${discordCommands}`, - inline: true, - }, - { name: "\u200B", value: "\u200B" }, - { - name: "**Minecraft Information**:", - value: `Bot Username: \`${bot.username}\`\nPrefix: \`${config.minecraft.bot.prefix}\`\nSkyBlock Events: \`${ - config.minecraft.skyblockEventsNotifications.enabled ? "enabled" : "disabled" - }\`\nAuto Accept: \`${ - config.minecraft.guildRequirements.autoAccept ? "enabled" : "disabled" - }\`\nGuild Experience Requirement: \`${config.minecraft.guild.guildExp.toLocaleString()}\`\nUptime: Online since \nVersion: \`${require("../../../package.json").version}\`\n`, - inline: true, - }, - { - name: `**Discord Information**`, - value: `Guild Channel: ${ - config.discord.channels.guildChatChannel ? `<#${config.discord.channels.guildChatChannel}>` : "None" - }\nOfficer Channel: ${ - config.discord.channels.officerChannel ? `<#${config.discord.channels.officerChannel}>` : "None" - }\nGuild Logs Channel: ${ - config.discord.channels.loggingChannel ? `<#${config.discord.channels.loggingChannel}>` : "None" - }\nDebugging Channel: ${ - config.discord.channels.debugChannel ? `<#${config.discord.channels.debugChannel}>` : "None" - }\nCommand Role: <@&${config.discord.commands.commandRole}>\nMessage Mode: \`${ - config.discord.other.messageMode - }\`\nFilter: \`${config.discord.other.filterMessages ? "enabled" : "disabled"}\`\nJoin Messages: \`${ - config.discord.other.joinMessage ? "enabled" : "disabled" - }\``, - inline: true, - }, - ) - .setFooter({ - text: "by @duckysolucky | /help [command] for more information", - iconURL: "https://imgur.com/tgwQJTX.png", - }); - await interaction.followUp({ embeds: [infoEmbed] }); - }, -}; +function formatOptions(name, required) { + return replaceVariables(required ? ` ({${name}})` : ` [{${name}}]`, { username: "u" }) + .replaceAll("{", "") + .replaceAll("}", ""); +} function getCommands(commands) { const discordCommands = commands .map(({ name, options }) => { - const optionsString = options?.map(({ name, required }) => (required ? ` (${name})` : ` [${name}]`)).join(""); + const optionsString = options?.map(({ name, required }) => formatOptions(name, required)).join(""); return `- \`${name}${optionsString ? optionsString : ""}\`\n`; }) .join(""); @@ -82,9 +23,7 @@ function getCommands(commands) { .filter((file) => file.endsWith(".js")) .map((file) => { const command = new (require(`../../minecraft/commands/${file}`))(); - const optionsString = command.options - ?.map(({ name, required }) => (required ? ` (${name})` : ` [${name}]`)) - .join(""); + const optionsString = command.options?.map(({ name, required }) => formatOptions(name, required)).join(""); return `- \`${command.name}${optionsString}\`\n`; }) @@ -92,3 +31,71 @@ function getCommands(commands) { return { discordCommands, minecraftCommands }; } + +module.exports = { + name: "info", + description: "Shows information about the bot.", + requiresBot: true, + getCommands, + execute: async (interaction) => { + try { + if (bot === undefined || bot._client.chat === undefined) { + throw new HypixelDiscordChatBridgeError("Bot doesn't seem to be connected to Hypixel. Please try again."); + } + + const { discordCommands, minecraftCommands } = getCommands(interaction.client.commands); + + const infoEmbed = new EmbedBuilder() + .setColor(0x0099ff) + .setTitle("Hypixel Bridge Bot Commands") + .addFields( + { + name: "**Minecraft Commands**: ", + value: `${minecraftCommands}`, + inline: true, + }, + { + name: "**Discord Commands**: ", + value: `${discordCommands}`, + inline: true, + }, + { name: "\u200B", value: "\u200B" }, + { + name: "**Minecraft Information**:", + value: `Bot Username: \`${bot.username}\`\nPrefix: \`${config.minecraft.bot.prefix}\`\nSkyBlock Events: \`${ + config.minecraft.skyblockEventsNotifications.enabled ? "enabled" : "disabled" + }\`\nAuto Accept: \`${ + config.minecraft.guildRequirements.autoAccept ? "enabled" : "disabled" + }\`\nGuild Experience Requirement: \`${config.minecraft.guild.guildExp.toLocaleString()}\`\nUptime: Online since \nVersion: \`${require("../../../package.json").version}\`\n`, + inline: true, + }, + { + name: `**Discord Information**`, + value: `Guild Channel: ${ + config.discord.channels.guildChatChannel ? `<#${config.discord.channels.guildChatChannel}>` : "None" + }\nOfficer Channel: ${ + config.discord.channels.officerChannel ? `<#${config.discord.channels.officerChannel}>` : "None" + }\nGuild Logs Channel: ${ + config.discord.channels.loggingChannel ? `<#${config.discord.channels.loggingChannel}>` : "None" + }\nDebugging Channel: ${ + config.discord.channels.debugChannel ? `<#${config.discord.channels.debugChannel}>` : "None" + }\nCommand Role: <@&${config.discord.commands.commandRole}>\nMessage Mode: \`${ + config.discord.other.messageMode + }\`\nFilter: \`${config.discord.other.filterMessages ? "enabled" : "disabled"}\`\nJoin Messages: \`${ + config.discord.other.joinMessage ? "enabled" : "disabled" + }\``, + inline: true, + }, + ) + .setFooter({ + text: "by @duckysolucky | /help [command] for more information", + iconURL: "https://imgur.com/tgwQJTX.png", + }); + await interaction.followUp({ embeds: [infoEmbed] }); + } catch (e) { + console.log(e); + } + }, +}; diff --git a/src/discord/commands/inviteCommand.js b/src/discord/commands/inviteCommand.js index 9a6bec12..43594ad7 100644 --- a/src/discord/commands/inviteCommand.js +++ b/src/discord/commands/inviteCommand.js @@ -7,7 +7,7 @@ module.exports = { requiresBot: true, options: [ { - name: "name", + name: "username", description: "Minecraft Username", type: 3, required: true, @@ -15,7 +15,7 @@ module.exports = { ], execute: async (interaction) => { - const name = interaction.options.getString("name"); + const name = interaction.options.getString("username"); bot.chat(`/g invite ${name}`); const embed = new SuccessEmbed(`Successfully invited **${name}** to the guild.`); diff --git a/src/discord/commands/kickCommand.js b/src/discord/commands/kickCommand.js index 49156c04..e77f544c 100644 --- a/src/discord/commands/kickCommand.js +++ b/src/discord/commands/kickCommand.js @@ -7,7 +7,7 @@ module.exports = { requiresBot: true, options: [ { - name: "name", + name: "username", description: "Minecraft Username", type: 3, required: true, @@ -21,7 +21,7 @@ module.exports = { ], execute: async (interaction) => { - const [name, reason] = [interaction.options.getString("name"), interaction.options.getString("reason")]; + const [name, reason] = [interaction.options.getString("username"), interaction.options.getString("reason")]; bot.chat(`/g kick ${name} ${reason}`); const embed = new SuccessEmbed(`Successfully kicked **${name}** from the guild.`); diff --git a/src/discord/commands/linkedCommand.js b/src/discord/commands/linkedCommand.js index c7814a48..b3186993 100644 --- a/src/discord/commands/linkedCommand.js +++ b/src/discord/commands/linkedCommand.js @@ -17,7 +17,7 @@ module.exports = { required: false, }, { - name: "name", + name: "username", description: "Minecraft Username", type: 3, required: false, @@ -39,7 +39,7 @@ module.exports = { } const user = interaction.options.getUser("user"); - const name = interaction.options.getString("name"); + const name = interaction.options.getString("username"); if (!user && !name) { throw new HypixelDiscordChatBridgeError("Please provide a user or a name."); } diff --git a/src/discord/commands/muteCommand.js b/src/discord/commands/muteCommand.js index f5bf8dce..ca60fa27 100644 --- a/src/discord/commands/muteCommand.js +++ b/src/discord/commands/muteCommand.js @@ -7,7 +7,7 @@ module.exports = { requiresBot: true, options: [ { - name: "name", + name: "username", description: "Minecraft Username", type: 3, required: true, @@ -21,7 +21,7 @@ module.exports = { ], execute: async (interaction) => { - const [name, time] = [interaction.options.getString("name"), interaction.options.getString("time")]; + const [name, time] = [interaction.options.getString("username"), interaction.options.getString("time")]; bot.chat(`/g mute ${name} ${time}`); const embed = new SuccessEmbed(`Successfully muted **${name}** for ${time}.`); diff --git a/src/discord/commands/promoteCommand.js b/src/discord/commands/promoteCommand.js index a8d973ef..5fe555c0 100644 --- a/src/discord/commands/promoteCommand.js +++ b/src/discord/commands/promoteCommand.js @@ -7,7 +7,7 @@ module.exports = { requiresBot: true, options: [ { - name: "name", + name: "username", description: "Minecraft Username", type: 3, required: true, @@ -15,7 +15,7 @@ module.exports = { ], execute: async (interaction) => { - const name = interaction.options.getString("name"); + const name = interaction.options.getString("username"); bot.chat(`/g promote ${name}`); const embed = new SuccessEmbed(`Successfully promoted \`${name}\` by one guild rank.`); diff --git a/src/discord/commands/unmuteCommand.js b/src/discord/commands/unmuteCommand.js index a279e036..c1f98dcc 100644 --- a/src/discord/commands/unmuteCommand.js +++ b/src/discord/commands/unmuteCommand.js @@ -7,7 +7,7 @@ module.exports = { requiresBot: true, options: [ { - name: "name", + name: "username", description: "Minecraft Username", type: 3, required: true, @@ -15,7 +15,7 @@ module.exports = { ], execute: async (interaction) => { - const name = interaction.options.getString("name"); + const name = interaction.options.getString("username"); bot.chat(`/g unmute ${name}`); const embed = new EmbedBuilder() diff --git a/src/discord/commands/verifyCommand.js b/src/discord/commands/verifyCommand.js index 86cb2ba2..9ef48579 100644 --- a/src/discord/commands/verifyCommand.js +++ b/src/discord/commands/verifyCommand.js @@ -10,7 +10,7 @@ module.exports = { verificationCommand: true, options: [ { - name: "name", + name: "username", description: "Minecraft Username", type: 3, required: true, @@ -45,7 +45,7 @@ module.exports = { } } - const username = interaction.options.getString("name"); + const username = interaction.options.getString("username"); const { socialMedia, nickname, uuid } = await hypixelRebornAPI.getPlayer(username); if (Object.values(linked).includes(uuid) === true) { if (bypassChecks === true) { From 33cfb3b4419e726834f55fcfd468c7d482a5e1ee Mon Sep 17 00:00:00 2001 From: Jacob <55346310+Kathund@users.noreply.github.com> Date: Wed, 11 Dec 2024 21:25:38 +0800 Subject: [PATCH 4/8] Update how linked.json is created (#288) --- data/linked.json | 1 - src/Application.js | 12 ++++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) delete mode 100644 data/linked.json diff --git a/data/linked.json b/data/linked.json deleted file mode 100644 index 0967ef42..00000000 --- a/data/linked.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/src/Application.js b/src/Application.js index 4db89df5..fe6a9a1b 100644 --- a/src/Application.js +++ b/src/Application.js @@ -1,12 +1,16 @@ const MinecraftManager = require("./minecraft/MinecraftManager.js"); +const { existsSync, mkdirSync, writeFileSync } = require("fs"); const DiscordManager = require("./discord/DiscordManager.js"); const webManager = require("./web/WebsiteManager.js"); -// eslint-disable-next-line no-unused-vars -const Configuration = require("./Configuration.js"); -// eslint-disable-next-line no-unused-vars -const Updater = require("./Updater.js"); class Application { + constructor() { + require("./Configuration.js"); + require("./Updater.js"); + if (!existsSync("./data/")) mkdirSync("./data/", { recursive: true }); + if (!existsSync("./data/linked.json")) writeFileSync("./data/linked.json", JSON.stringify({})); + } + async register() { this.discord = new DiscordManager(this); this.minecraft = new MinecraftManager(this); From e5b07169810c7e93b4876f90a94504dbb0cd3889 Mon Sep 17 00:00:00 2001 From: Jacob Date: Wed, 11 Dec 2024 21:36:54 +0800 Subject: [PATCH 5/8] Fix Blacklist --- src/discord/commands/blacklistCommand.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/discord/commands/blacklistCommand.js b/src/discord/commands/blacklistCommand.js index 32d9796c..8e73d552 100644 --- a/src/discord/commands/blacklistCommand.js +++ b/src/discord/commands/blacklistCommand.js @@ -1,4 +1,5 @@ const HypixelDiscordChatBridgeError = require("../../contracts/errorHandler.js"); +const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); const { SuccessEmbed } = require("../../contracts/embedHandler.js"); module.exports = { @@ -35,6 +36,8 @@ module.exports = { const name = interaction.options.getString("username"); const arg = interaction.options.getString("arg").toLowerCase(); + bot.chat("/lobby megawalls"); + await delay(250); if (arg == "add") { bot.chat(`/ignore add ${name}`); } else if (arg == "remove") { @@ -42,6 +45,8 @@ module.exports = { } else { throw new HypixelDiscordChatBridgeError("Invalid Usage: `/ignore [add/remove] [name]`."); } + await delay(250); + bot.chat("/limbo"); const embed = new SuccessEmbed( `Successfully ${arg == "add" ? "added" : "removed"} \`${name}\` ${arg == "add" ? "to" : "from"} the blacklist.`, From 640a4eb91540c944d0a54193a383e056de3af39d Mon Sep 17 00:00:00 2001 From: Jacob Date: Wed, 11 Dec 2024 21:40:42 +0800 Subject: [PATCH 6/8] Change Message Checks --- src/minecraft/handlers/ChatHandler.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/minecraft/handlers/ChatHandler.js b/src/minecraft/handlers/ChatHandler.js index 1af4668f..9fff3f04 100644 --- a/src/minecraft/handlers/ChatHandler.js +++ b/src/minecraft/handlers/ChatHandler.js @@ -848,16 +848,17 @@ class StateHandler extends eventHandler { isAlreadyBlacklistedMessage(message) { return ( - message.includes(`You've already ignored that player! /ignore remove Player to unignore them!`) && + message.includes(`You've already blocked that player! /block remove to unblock them!`) && !message.includes(":") ); } + isBlacklistRemovedMessage(message) { - return message.startsWith("Removed") && message.includes("from your ignore list.") && !message.includes(":"); + return message.startsWith("Unblocked") && message.endsWith(".") && !message.includes(":"); } isBlacklistMessage(message) { - return message.startsWith("Added") && message.includes("to your ignore list.") && !message.includes(":"); + return message.startsWith("Blocked") && message.endsWith(".") && !message.includes(":"); } isGuildMessage(message) { @@ -1082,7 +1083,7 @@ class StateHandler extends eventHandler { return; } - const linkedUser = Object.values(linked).find((u) => player) + const linkedUser = Object.values(linked).find((u) => player); if (linkedUser === undefined) { return; } From 4bb66b73702511c0449cd8b1e8370cc813f1acbd Mon Sep 17 00:00:00 2001 From: Jacob Date: Sun, 15 Dec 2024 10:26:25 +0800 Subject: [PATCH 7/8] Remove Small API Request --- API/functions/getLatestProfile.js | 10 ++-------- API/stats/hotm.js | 20 +------------------- src/minecraft/commands/forgeCommand.js | 2 +- src/minecraft/commands/hotmCommand.js | 6 ++---- src/minecraft/commands/skyblockCommand.js | 2 +- 5 files changed, 7 insertions(+), 33 deletions(-) diff --git a/API/functions/getLatestProfile.js b/API/functions/getLatestProfile.js index 704a0e0f..465f29ed 100644 --- a/API/functions/getLatestProfile.js +++ b/API/functions/getLatestProfile.js @@ -23,21 +23,16 @@ async function getLatestProfile(uuid, options = { museum: false, garden: false } } } - const [{ data: playerRes }, { data: profileRes }] = await Promise.all([ - axios.get(`https://api.hypixel.net/v2/player?key=${config.minecraft.API.hypixelAPIkey}&uuid=${uuid}`), + const [{ data: profileRes }] = await Promise.all([ axios.get(`https://api.hypixel.net/v2/skyblock/profiles?key=${config.minecraft.API.hypixelAPIkey}&uuid=${uuid}`), ]).catch((error) => { throw error?.response?.data?.cause ?? "Request to Hypixel API failed. Please try again!"; }); - if (playerRes.success === false || profileRes.success === false) { + if (profileRes.success === false) { throw "Request to Hypixel API failed. Please try again!"; } - if (playerRes.player == null) { - throw "Player not found. It looks like this player has never joined the Hypixel."; - } - if (profileRes.profiles == null || profileRes.profiles.length == 0) { throw "Player has no SkyBlock profiles."; } @@ -57,7 +52,6 @@ async function getLatestProfile(uuid, options = { museum: false, garden: false } profiles: profileRes.profiles, profile: profile, profileData: profileData, - playerRes: playerRes.player, uuid: uuid, ...(options.museum ? await getMuseum(profileData.profile_id, uuid) : {}), ...(options.garden ? await getGarden(profileData.profile_id) : {}), diff --git a/API/stats/hotm.js b/API/stats/hotm.js index 5b3e4dc7..042992d7 100644 --- a/API/stats/hotm.js +++ b/API/stats/hotm.js @@ -4,25 +4,8 @@ const miningConst = require("../constants/mining.js"); const calcSkill = require("../constants/skills.js"); const moment = require("moment"); -module.exports = (player, profile) => { +module.exports = (profile) => { try { - const commissions = { - total: player?.achievements?.skyblock_hard_working_miner ?? 0, - milestone: 0, - }; - - // CREDITS: https://github.com/SkyCryptWebsite/SkyCrypt/blob/b9842bea6f1494fa2d2fd005b64f57d84646c188/src/stats/mining.js#L129 - if (profile.objectives?.tutorial !== undefined) { - for (const key of profile.objectives.tutorial) { - if (key.startsWith("commission_milestone_reward_mining_xp_tier_") === false) { - continue; - } - - const tier = parseInt(key.slice(43)); - commissions.milestone = Math.max(commissions.milestone, tier); - } - } - const forgeItems = []; if (profile.forge?.forge_processes?.forge_1) { const forge = Object.values(profile.forge.forge_processes.forge_1); @@ -80,7 +63,6 @@ module.exports = (player, profile) => { }, level: calcSkill("hotm", profile?.mining_core?.experience || 0), ability: titleCase(profile?.mining_core?.selected_pickaxe_ability || "none", true), - commissions: commissions, forge: forgeItems, }; } catch (error) { diff --git a/src/minecraft/commands/forgeCommand.js b/src/minecraft/commands/forgeCommand.js index 81cd8589..4250f4aa 100644 --- a/src/minecraft/commands/forgeCommand.js +++ b/src/minecraft/commands/forgeCommand.js @@ -27,7 +27,7 @@ class ForgeCommand extends minecraftCommand { username = formatUsername(username, data.profileData?.game_mode); - const hotm = getHotm(data.playerRes, data.profile); + const hotm = getHotm(data.profile); if (hotm == null) { // eslint-disable-next-line no-throw-literal diff --git a/src/minecraft/commands/hotmCommand.js b/src/minecraft/commands/hotmCommand.js index 95fae059..0cd4040f 100644 --- a/src/minecraft/commands/hotmCommand.js +++ b/src/minecraft/commands/hotmCommand.js @@ -28,7 +28,7 @@ class HotmCommand extends minecraftCommand { username = formatUsername(username, data.profileData?.game_mode); - const hotm = getHotm(data.playerRes, data.profile); + const hotm = getHotm(data.profile); if (hotm == null) { // eslint-disable-next-line no-throw-literal @@ -42,9 +42,7 @@ class HotmCommand extends minecraftCommand { hotm.powder.gemstone.total )} | Mithril Powder: ${formatNumber(hotm.powder.mithril.total)} | Glacite Powder: ${formatNumber( hotm.powder.glacite.total - )} | Selected Ability: ${hotm.ability} | Commissions Milestone: ${ - hotm.commissions.milestone - } (${hotm.commissions.total.toLocaleString()})` + )} | Selected Ability: ${hotm.ability}` ); } catch (error) { this.send(`/gc [ERROR] ${error}`); diff --git a/src/minecraft/commands/skyblockCommand.js b/src/minecraft/commands/skyblockCommand.js index 9d9ee66e..50203452 100644 --- a/src/minecraft/commands/skyblockCommand.js +++ b/src/minecraft/commands/skyblockCommand.js @@ -41,7 +41,7 @@ class SkyblockCommand extends minecraftCommand { }), getDungeons(data.profile), getTalismans(data.profile), - getHotm(data.player, data.profile), + getHotm(data.profile), ]); const skillAverage = ( From a0d0ede83c113c22c48d14ce6b624554bca89db7 Mon Sep 17 00:00:00 2001 From: CarsonCodes <77174760+CarsonCodess@users.noreply.github.com> Date: Tue, 24 Dec 2024 19:04:35 -0500 Subject: [PATCH 8/8] Special Mayor Command (#292) * Special Mayor Command Added a special mayor command, gives time until next special mayor along with who it is speculated to be. * Update specialMayorCommand.js --- src/minecraft/commands/specialMayorCommand.js | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 src/minecraft/commands/specialMayorCommand.js diff --git a/src/minecraft/commands/specialMayorCommand.js b/src/minecraft/commands/specialMayorCommand.js new file mode 100644 index 00000000..21a3bdf9 --- /dev/null +++ b/src/minecraft/commands/specialMayorCommand.js @@ -0,0 +1,78 @@ +const minecraftCommand = require("../../contracts/minecraftCommand.js"); + + +/* +Derpy = 368 mod 24 = 8 +Jerry = 376 mod 24 = 16 +Scorpius = 384 mod 24 = 0 +https://hypixel-skyblock.fandom.com/wiki/Mayor_Election#Special_Candidates_Election_Cycle +*/ + +const hourMs = 50000; +const dayMs = 24 * hourMs; +const monthLength = 31; +const yearLength = 12; + +const monthMs = monthLength * dayMs; +const yearMs = yearLength * monthMs; + +const yearZero = 1560275700000; + +const currentSkyblockYear = timeToSkyblockYear(Date.now()); + +var yearsUntilSpecial = 0; +var diffSkyblockYear = currentSkyblockYear; +var specialMayor = ""; + + +function timeToSkyblockYear(time) { + return Math.floor((time - yearZero) / yearMs) + 1; + } + +function getSpecialMayor(skyblockYear) { + if (diffSkyblockYear % 24 == 8){ + specialMayor = "Derpy"; + } else if (diffSkyblockYear % 24 == 16){ + specialMayor = "Jerry"; + } else if (diffSkyblockYear % 24 == 0){ + specialMayor = "Scorpius"; + } else { + specialMayor = "Error!"; + } + return specialMayor; +} + +class SpecialMayorCommand extends minecraftCommand { + constructor(minecraft) { + super(minecraft); + + this.name = "specialmayor"; + this.aliases = ["specmayor"]; + this.description = "How many years until next special mayor, along with speculated special mayor."; + this.options = []; + } + + async onCommand() { + try { + + if (currentSkyblockYear % 8 == 0){ + specialMayor = getSpecialMayor(currentSkyblockYear); + this.send(`/gc Special Mayor this year! It is speculated to be ${specialMayor}.`); + } else { + while (diffSkyblockYear % 8 != 0){ + yearsUntilSpecial += 1; + diffSkyblockYear += 1; + specialMayor = getSpecialMayor(diffSkyblockYear); + } + this.send(`/gc Not Special Mayor, ${yearsUntilSpecial} years until the next one! It is speculated to be ${specialMayor}.`); + } + + } catch (error) { + console.log(error) + this.send(`/gc [ERROR] ${error}`); + } + } + } + + module.exports = SpecialMayorCommand; + \ No newline at end of file