From 77a7cfa32b5016583bdde2e24a1b34ccac05149a Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Wed, 21 May 2025 15:39:25 -0700 Subject: [PATCH 01/61] initial stuff --- src/commands/farm/command.ts | 11 + src/commands/farm/info.ts | 132 ++++++++++ src/commands/farm/search.ts | 24 ++ src/commands/farm/temp.ts | 475 +++++++++++++++++++++++++++++++++++ 4 files changed, 642 insertions(+) create mode 100644 src/commands/farm/command.ts create mode 100644 src/commands/farm/info.ts create mode 100644 src/commands/farm/search.ts create mode 100644 src/commands/farm/temp.ts diff --git a/src/commands/farm/command.ts b/src/commands/farm/command.ts new file mode 100644 index 0000000..d69012f --- /dev/null +++ b/src/commands/farm/command.ts @@ -0,0 +1,11 @@ +import { CommandAccess, CommandGroup, CommandType } from '../../classes/commands/index.js'; + +const command = new CommandGroup({ + name: 'farm', + description: '', + execute: () => undefined, + access: CommandAccess.Everywhere, + type: CommandType.Group, +}); + +export default command; diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts new file mode 100644 index 0000000..ca64e27 --- /dev/null +++ b/src/commands/farm/info.ts @@ -0,0 +1,132 @@ +import { UserSettings } from 'api/elite.js'; +import { CommandAccess, CommandType, EliteCommand, SlashCommandOptionType } from 'classes/commands/index.js'; +import { AutocompleteInteraction, ChatInputCommandInteraction } from 'discord.js'; +import { farmsData } from './temp.js'; + +const command = new EliteCommand({ + name: 'info', + description: 'Get info about a farm design!', + access: CommandAccess.Everywhere, + type: CommandType.Slash, + subCommand: true, + options: { + design: { + name: 'design', + description: 'Select a farm design!', + type: SlashCommandOptionType.String, + required: true, + }, + direction: { + name: 'direction', + description: 'Optionally select the direction you face when farming, this helps to show the correct angles.', + type: SlashCommandOptionType.String, + autocomplete: autocomplete, + }, + flipped: { + name: 'flipped', + description: + 'Optionally select whether or not you flipped (mirrored) the original design, this helps to show the correct angles.', + type: SlashCommandOptionType.String, + autocomplete: autocomplete, + }, + depth_strider: { + name: 'depth strider', + description: 'Optionally select the depth strider level you use, this helps to show the correct speed.', + type: SlashCommandOptionType.String, + }, + version: { + name: 'version', + description: + 'Optionally select the Minecraft version you play on, this helps to show the correct speed for farms that use soul sand.', + type: SlashCommandOptionType.String, + }, + }, + execute: execute, +}); + +export const allowedDesigns = Object.entries(farmsData) + +const mcVersions = ['1.8.9', '1.21'] as const; +type Version = typeof mcVersions[number]; + +const depthStriderLevels = [1, 2, 3] as const; +type DSLevel = typeof depthStriderLevels[number]; + +const directions = ['North', 'South', 'East', 'West'] as const; +type Direction = typeof directions[number]; + +const autocompleteData: Record> = { + direction: directions.map((v) => ({ name: v, value: v })), + 'depth strider': depthStriderLevels.map((n) => ({ name: `Depth Strider ${n}`, value: n })), + version: mcVersions.map((v) => ({ name: v, value: v })), + design: allowedDesigns.map(([key, data]) => ({ name: data.name, value: key })), +}; + +async function autocomplete(interaction: AutocompleteInteraction) { + if (interaction.responded) return; + + const option = interaction.options.getFocused(true); + const options = autocompleteData[option.name]; + if (!options) return; + + const input = option.value.toLowerCase(); + + const filtered = options.filter((opt) => opt.name.toLowerCase().startsWith(input)); + + await interaction.respond(filtered); +} + +export default command; + +async function execute(interaction: ChatInputCommandInteraction, settings?: UserSettings) { + const versionRaw = interaction.options.getString('version', false)?.trim(); + const version = mcVersions.includes(versionRaw as Version) + ? (versionRaw as Version) + : undefined; + + const dsRaw = interaction.options.getString('depth_strider', false)?.trim(); + const dsLevel = depthStriderLevels.includes(Number(dsRaw) as DSLevel) + ? (Number(dsRaw) as DSLevel) + : undefined; + + const directionRaw = interaction.options.getString('direction', false)?.trim(); + const direction = directions.includes(directionRaw as Direction) + ? (directionRaw as Direction) + : undefined; + + const farm = farmsData[interaction.options.getString('design', true) as keyof typeof farmsData]; + + await interaction + .reply({ + content: `${calcSpeed(farm.speed.speed, farm.speed.soulSand, farm.speed.buildVersion, version, farm.speed.depthStrider, dsLevel)}`, + allowedMentions: { repliedUser: false }, + }) + .catch(() => undefined); + +} + +async function calcSpeed( + currentSpeed: number, + usesSoulSand?: boolean, + designVersion?: "1.8.9" | "1.21", + targetVersion?: "1.8.9" | "1.21", + currentDepthStrider?: 1 | 2 | 3, + targetDepthStrider?: 1 | 2 | 3, +): Promise { + const versionMultiplier = { + "1.8.9": 0.4, + "1.21": 0.5, + }; + + let speed = currentSpeed; + + if (currentDepthStrider && targetDepthStrider) { + speed *= targetDepthStrider / currentDepthStrider; + } + + if (usesSoulSand && designVersion && targetVersion) { + speed *= versionMultiplier[targetVersion] / versionMultiplier[designVersion]; + } + + return speed; +} diff --git a/src/commands/farm/search.ts b/src/commands/farm/search.ts new file mode 100644 index 0000000..2b77b82 --- /dev/null +++ b/src/commands/farm/search.ts @@ -0,0 +1,24 @@ +import { UserSettings } from 'api/elite.js'; +import { CommandAccess, CommandType, EliteCommand, SlashCommandOptionType } from 'classes/commands/index.js'; +import { AutocompleteInteraction, ChatInputCommandInteraction } from 'discord.js'; + +const command = new EliteCommand({ + name: 'info', + description: 'Get info about a farm design!', + access: CommandAccess.Everywhere, + type: CommandType.Slash, + subCommand: true, + options: { + design: { + name: 'crop', + description: 'Search for a farm design!', + type: SlashCommandOptionType.String, + required: true, + }, + }, + execute: execute, +}); + +export default command; + +async function execute(interaction: ChatInputCommandInteraction, settings?: UserSettings) {} diff --git a/src/commands/farm/temp.ts b/src/commands/farm/temp.ts new file mode 100644 index 0000000..11c563a --- /dev/null +++ b/src/commands/farm/temp.ts @@ -0,0 +1,475 @@ +import { Crop } from 'farming-weight'; + +interface farmInfo { + name: string; + description?: string; + crops: Crop[]; + speed: { + speed: number; + depthStrider?: 1 | 2 | 3; + soulSand: boolean; + buildVersion: "1.8.9" | "1.21" + method: 'straight' | 'running into wall' | 'angled into wall' | 'crouching'; + }; + angle: { + yaw: number; + pitch: number; + }; + bps: number; + laneDepth: number; + tutorials?: { + thread?: string; + video?: string; + garden?: string; + schematic?: string; + }; + authors?: string[]; + replacedBy?: string[]; + notes?: string[]; +} + +const blackCatNote = 'Despite the name, this farm **does not** use a black cat pet anymore'; + +export const farmsData: Record = { + idkdomPumpkin: { + name: 'IdkDom Melon/Pumpkin', + crops: [Crop.Melon, Crop.Pumpkin], + speed: { + speed: 155, + soulSand: false, + buildVersion: "1.8.9", + method: 'straight', + }, + angle: { + yaw: 0, + pitch: 28.5, + }, + bps: 19.5, + laneDepth: 3, + tutorials: { + video: 'https://www.youtube.com/watch?v=Zy_w332uUic', + garden: 'IdkDom', + }, + authors: ['IdkDom'], + replacedBy: ['easierMelon', 'chisslMelon'], + }, + blackCatMelon: { + name: 'SunTzu & MelonKingDe Black Cat Melon', + crops: [Crop.Melon, Crop.Pumpkin], + speed: { + speed: 400, + depthStrider: 3, + soulSand: true, + buildVersion: "1.8.9", + method: 'running into wall', + }, + angle: { + yaw: 0, + pitch: -59, + }, + bps: 19.8, + laneDepth: 3, + tutorials: { + thread: 'https://discord.com/channels/1096051612373487687/1159960881287942234', + video: 'https://www.youtube.com/watch?v=5k9c7qK0l58', + garden: 'MelonKingDe', + }, + authors: ['AgitatedSnake92', 'MelonKingDe', 'SunTzu101'], + replacedBy: ['easierMelon', 'chisslMelon'], + notes: [blackCatNote], + }, + easierMelon: { + name: 'Easier to Build Melon/Pumpkin', + crops: [Crop.Melon, Crop.Pumpkin], + speed: { + speed: 400, + depthStrider: 3, + soulSand: true, + buildVersion: "1.8.9", + method: 'running into wall', + }, + angle: { + yaw: 0, + pitch: -59, + }, + bps: 19.8, + laneDepth: 3, + tutorials: { + thread: 'https://discord.com/channels/1096051612373487687/1358514959247741068', + video: 'https://www.youtube.com/watch?v=s4HV0RyWcoI', + garden: 'IdkVenom', + }, + authors: ['AgitatedSnake92', 'MelonKingDe', 'SunTzu101', 'IdkVenom', 'DeadlyIPanda'], + }, + chisslMelon: { + name: 'Chissl Waterless Melon/Pumpkin', + crops: [Crop.Melon, Crop.Pumpkin], + speed: { + speed: 365, + soulSand: false, + buildVersion: "1.8.9", // todo: check + method: 'straight', // todo: check + }, + angle: { + yaw: 0, + pitch: 59, + }, + bps: 19.9, + laneDepth: 3, + tutorials: { + garden: 'Chissl', + }, + authors: ['Chissl'], + notes: ['Very difficult and time consuming to build, only worthwhile for extreme farmers'], + }, + dropdownWheat: { + name: 'Dropdown Wheat/Potato/Carrot/Netherwart', + crops: [Crop.Wheat, Crop.Potato, Crop.Carrot, Crop.NetherWart], + speed: { + speed: 93, + depthStrider: 3, + soulSand: false, + buildVersion: "1.8.9", + method: 'straight', + }, + angle: { + yaw: 0, + pitch: 3, + }, + bps: 19.8, + laneDepth: 5, + replacedBy: ['aceWheat', 'draipWheat', 'z109Wheat'], + notes: ['Annoying to use', 'Not infinite even at garden 15', 'Requires 5 plots, no less'], + }, + aceWheat: { + name: 'Ace Wheat/Potato/Carrot/Netherwart', + crops: [Crop.Wheat, Crop.Potato, Crop.Carrot, Crop.NetherWart], + speed: { + speed: 347, + depthStrider: 2, + soulSand: true, + buildVersion: "1.8.9", + method: 'running into wall', + }, + angle: { + yaw: 0, + pitch: 3, + }, + bps: 20, + laneDepth: 5, + tutorials: { + video: 'https://www.youtube.com/watch?v=hz4lGUz0JP4', + garden: 'SageUk', + }, + authors: ['AgitatedSnake92'], + }, + draipWheat: { + name: 'Draip Looping Wheat/Potato/Carrot/Netherwart', + crops: [Crop.Wheat, Crop.Potato, Crop.Carrot, Crop.NetherWart], + speed: { + speed: 328, + depthStrider: 3, + soulSand: false, + buildVersion: "1.8.9", + method: 'angled into wall', + }, + angle: { + yaw: 45, + pitch: 3, + }, + bps: 20, + laneDepth: 3, + tutorials: { + thread: 'https://discord.com/channels/1096051612373487687/1159965565218201721', + video: 'https://www.youtube.com/watch?v=gcJ5U7SyA-c', + }, + authors: ['Draip'], + notes: [ + 'Nice for pest farming because it loops, but it doesn require more plots than other designs', + 'Lanes can be as deep as you want, deeper means laneswitches are easier', + ], + }, + z109Wheat: { + name: 'Z109 Sprial Wheat/Potato/Carrot/Netherwart', + crops: [Crop.Wheat, Crop.Potato, Crop.Carrot, Crop.NetherWart], + speed: { + speed: 328, + depthStrider: 3, + soulSand: false, + buildVersion: "1.8.9", + method: 'angled into wall', + }, + angle: { + yaw: 45, + pitch: 3, + }, + bps: 20, + laneDepth: 3, + tutorials: { + thread: 'https://discord.com/channels/1096051612373487687/1253213095984365629', + video: 'https://www.youtube.com/watch?v=9yVNsafjOCA', + garden: 'Z109', + }, + authors: ['Z109'], + }, + blackCatWheat: { + name: 'Black Cat Wheat/Potato/Carrot', + crops: [Crop.Wheat, Crop.Potato, Crop.Carrot], + speed: { + speed: 347, + depthStrider: 2, + soulSand: true, + buildVersion: "1.8.9", + method: 'running into wall', + }, + angle: { + yaw: 0, + pitch: 3, + }, + bps: 19.9, + laneDepth: 5, + tutorials: { + thread: 'https://discord.com/channels/1096051612373487687/1159961248545374290', + video: 'https://www.youtube.com/watch?v=KBGIuETQI-g', + garden: 'MelonKingDe', + }, + authors: ['AgitatedSnake92', 'MelonKingDe', 'SunTzu101'], + replacedBy: ['aceWheat', 'draipWheat', 'z109Wheat'], + notes: [blackCatNote], + }, + blackCatNetherwart: { + name: 'Black Cat Nether Wart', + crops: [Crop.NetherWart], + speed: { + speed: 347, + depthStrider: 2, + soulSand: true, + buildVersion: "1.8.9", + method: 'running into wall', + }, + angle: { + yaw: 0, + pitch: 3, + }, + bps: 19.9, + laneDepth: 5, + tutorials: { + thread: 'https://discord.com/channels/1096051612373487687/1159961642952556636', + video: 'https://www.youtube.com/watch?v=n218KDmL-5s', + garden: 'MelonKingDe', + }, + authors: ['AgitatedSnake92', 'MelonKingDe', 'SunTzu101'], + replacedBy: ['aceWheat', 'draipWheat', 'z109Wheat'], + notes: [blackCatNote], + }, + sdsMushroom: { + name: 'Slanted Downward Spiral (SDS) Mushroom', + crops: [Crop.Mushroom], + speed: { + speed: 233, + depthStrider: 3, + soulSand: true, + buildVersion: "1.8.9", + method: 'angled into wall', + }, + angle: { + yaw: 16, + pitch: 5.5, + }, + bps: 19.7, + laneDepth: 4, + tutorials: { + thread: 'https://discord.com/channels/1096051612373487687/1159960305300930631', + video: 'https://www.youtube.com/watch?v=QyWf0DO831g', + garden: 'MelonKingDe', + }, + authors: ['AgitatedSnake92', 'MelonKingDe', 'SunTzu101'], + replacedBy: ['idkpoisonMushroom'], + }, + idkpoisonMushroom: { + name: 'IdkPoison_ Mushroom', + crops: [Crop.Mushroom], + speed: { + speed: 259, + soulSand: false, + buildVersion: "1.8.9", + method: 'angled into wall', + }, + angle: { + yaw: 0, // todo: fix + pitch: 0, + }, + bps: 19.9, + laneDepth: 4, + tutorials: { + garden: 'IdkPoison_', + }, + authors: ['IdkPoison_'], + }, + blackCatCocoa: { + name: 'Black Cat Cocoa', + crops: [Crop.CocoaBeans], + speed: { + speed: 400, + depthStrider: 3, + soulSand: true, + buildVersion: "1.8.9", + method: 'running into wall', + }, + angle: { + yaw: 0, + pitch: -45, + }, + bps: 19.95, + laneDepth: 3, + tutorials: { + thread: 'https://discord.com/channels/1096051612373487687/1159959995329298443', + video: 'https://www.youtube.com/watch?v=WWR2duiwxK4', + garden: 'FarmingHub', + }, + authors: ['AgitatedSnake92'], + notes: [blackCatNote], + }, + singleLaneCocoa: { + name: 'Single Lane Cocoa', + crops: [Crop.CocoaBeans], + speed: { + speed: 215, + soulSand: false, + buildVersion: "1.8.9", + method: 'running into wall', + }, + angle: { + yaw: 0, + pitch: -45, + }, + bps: 19.97, + laneDepth: 3, + tutorials: { + garden: 'not_a_cowfr', + }, + authors: ['not a cow', 'Binrich'], + notes: ["Easier to build than regular cocoa, but wont work if you don't hold D"], + }, + blackCatCactus: { + name: 'Black Cat Cactus', + crops: [Crop.Cactus], + speed: { + speed: 464, + depthStrider: 3, + soulSand: false, + buildVersion: "1.8.9", + method: 'straight', + }, + angle: { + yaw: 0, + pitch: 0, + }, + bps: 19.9, + laneDepth: 1, + tutorials: { + thread: 'https://discord.com/channels/1096051612373487687/1159959766748119050', + video: 'https://www.youtube.com/watch?v=Kj7qxeq1jEw', + garden: 'MelonKingDe', + }, + authors: ['AgitatedSnake92', 'MelonKingDe', 'SunTzu101'], + notes: [ + 'Despite the name, this farm **does not** use a black cat pet anymore, instead, cactus knife raises speed cap now', + ], + }, + aceCactus: { + name: 'Ace Cactus', + crops: [Crop.Cactus], + speed: { + speed: 464, + depthStrider: 3, + soulSand: false, + buildVersion: "1.8.9", + method: 'straight', + }, + angle: { + yaw: 0, + pitch: 0, + }, + bps: 19.9, + laneDepth: 1, + tutorials: { + garden: 'LunaSappho', + }, + authors: ['AgitatedSnake92'], + notes: ["Don't worry about getting over 400 speed, cactus knife raises speed cap by 100"], + }, + regularCane: { + name: 'Regular Sugar Cane', + crops: [Crop.SugarCane], + speed: { + speed: 328, + soulSand: false, + buildVersion: "1.8.9", + method: 'angled into wall', + }, + angle: { + yaw: 45, + pitch: 0, + }, + bps: 19.98, + laneDepth: 2, + tutorials: { + thread: 'https://discord.com/channels/1096051612373487687/1159960545487761479', + video: 'https://www.youtube.com/watch?v=nQ5yjQU9gmo', + garden: 'FarmingHub', + }, + }, + farminghubCane: { + name: 'FarmingHub Sugar Cane', + crops: [Crop.SugarCane], + speed: { + speed: 328, + soulSand: false, + buildVersion: "1.8.9", + method: 'angled into wall', + }, + angle: { + yaw: 45, + pitch: 0, + }, + bps: 20, + laneDepth: 2, + tutorials: { + garden: 'FarmingHub', + }, + authors: ['AgitatedSnake92'], + }, +}; + +// designs +// ✅=done ❌=not done yet + +// sds mush ✅ +// idkpoison mush ✅ + +// draip wheat ✅ +// ace wheat (sageuk as garden?) ✅ +// z109 wheat ✅ +// clovis' wierd ass dropdown design ❌ +// black cat wheat ✅ + +// black cat netherwart ✅ + +// cow cocoa ✅ +// farminghub cocoa ✅ + +// ace cactus (visi luna) ✅ +// regular cactus ❌ +// black cat cactus ✅ + +// regular cane, link melonking vid ✅ +// farminghub cane ✅ + +// maybe have farm info contain which keys always held and which keys alernate between + +// maybe clac method used via things like +// 0 yaw = straight +// non 0 yaw = angled into wall +// 0 yaw and movement key si always held = running into wall +// idk how it would work for like draip and z109 though, maybe not a good idea then From eec47af87936a40eb7f84dd45a0b93846e46cfde Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Thu, 22 May 2025 09:42:16 -0700 Subject: [PATCH 02/61] some changes agi told me to make --- src/commands/farm/temp.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/commands/farm/temp.ts b/src/commands/farm/temp.ts index 11c563a..b97d7b5 100644 --- a/src/commands/farm/temp.ts +++ b/src/commands/farm/temp.ts @@ -99,7 +99,7 @@ export const farmsData: Record = { video: 'https://www.youtube.com/watch?v=s4HV0RyWcoI', garden: 'IdkVenom', }, - authors: ['AgitatedSnake92', 'MelonKingDe', 'SunTzu101', 'IdkVenom', 'DeadlyIPanda'], + authors: ['AgitatedSnake92', 'MelonKingDe', 'IdkVenom', 'DeadlyIPanda'], }, chisslMelon: { name: 'Chissl Waterless Melon/Pumpkin', @@ -119,7 +119,7 @@ export const farmsData: Record = { tutorials: { garden: 'Chissl', }, - authors: ['Chissl'], + authors: ['AgitatedSnake92', 'Chissl'], notes: ['Very difficult and time consuming to build, only worthwhile for extreme farmers'], }, dropdownWheat: { @@ -210,7 +210,7 @@ export const farmsData: Record = { video: 'https://www.youtube.com/watch?v=9yVNsafjOCA', garden: 'Z109', }, - authors: ['Z109'], + authors: ['AgitatedSnake92', 'Z109'], }, blackCatWheat: { name: 'Black Cat Wheat/Potato/Carrot', @@ -304,7 +304,7 @@ export const farmsData: Record = { tutorials: { garden: 'IdkPoison_', }, - authors: ['IdkPoison_'], + authors: ['AgitatedSnake92', 'IdkPoison_'], }, blackCatCocoa: { name: 'Black Cat Cocoa', @@ -320,7 +320,7 @@ export const farmsData: Record = { yaw: 0, pitch: -45, }, - bps: 19.95, + bps: 19.98, laneDepth: 3, tutorials: { thread: 'https://discord.com/channels/1096051612373487687/1159959995329298443', @@ -349,7 +349,7 @@ export const farmsData: Record = { garden: 'not_a_cowfr', }, authors: ['not a cow', 'Binrich'], - notes: ["Easier to build than regular cocoa, but wont work if you don't hold D"], + notes: ["Easier to build and use than regular cocoa, but wont work if you don't hold D (but doing so is better anyway so it doesn't really matter)"], }, blackCatCactus: { name: 'Black Cat Cactus', @@ -417,7 +417,7 @@ export const farmsData: Record = { tutorials: { thread: 'https://discord.com/channels/1096051612373487687/1159960545487761479', video: 'https://www.youtube.com/watch?v=nQ5yjQU9gmo', - garden: 'FarmingHub', + garden: 'MelonKingDe', }, }, farminghubCane: { From 9fe5d7f1678e620a07d60a7afd9dceebfdb0d293 Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Thu, 22 May 2025 10:00:36 -0700 Subject: [PATCH 03/61] add commands.md entries --- COMMANDS.md | 21 +++++++++++++++++++++ src/commands/farm/info.ts | 1 + 2 files changed, 22 insertions(+) diff --git a/COMMANDS.md b/COMMANDS.md index 149e535..4469dab 100644 --- a/COMMANDS.md +++ b/COMMANDS.md @@ -120,6 +120,27 @@ Link your Minecraft account so you no longer need to specify your player name! I verify +--- +### /farm info +Get info on a specific farm design including, angles, speeds, tutorials and more. + +**Usage:** `/farm info` \ +`[design]: ` +`(direction): ` +`(depth strider): ` +`(version): ` + +farm info + +--- +### /farm search +Search for farm designs for a specific crop. + +**Usage:** `/farm search` \ +`[crop]: ` + +farm search + ## Info Commands ### /info diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index ca64e27..2f9f949 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -22,6 +22,7 @@ const command = new EliteCommand({ type: SlashCommandOptionType.String, autocomplete: autocomplete, }, + // maybe just put both possible yaws for farms that this would affect? this would probably just be confusing for most people flipped: { name: 'flipped', description: From e609e7d69e93cbdaa0b8652508cbae6b2741c1dd Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Thu, 22 May 2025 10:03:35 -0700 Subject: [PATCH 04/61] lint --- src/commands/farm/info.ts | 57 +++++++++++++++++---------------------- src/commands/farm/temp.ts | 42 +++++++++++++++-------------- 2 files changed, 47 insertions(+), 52 deletions(-) diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index 2f9f949..6b8974e 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -45,22 +45,22 @@ const command = new EliteCommand({ execute: execute, }); -export const allowedDesigns = Object.entries(farmsData) +export const allowedDesigns = Object.entries(farmsData); const mcVersions = ['1.8.9', '1.21'] as const; -type Version = typeof mcVersions[number]; +type Version = (typeof mcVersions)[number]; const depthStriderLevels = [1, 2, 3] as const; -type DSLevel = typeof depthStriderLevels[number]; +type DSLevel = (typeof depthStriderLevels)[number]; const directions = ['North', 'South', 'East', 'West'] as const; -type Direction = typeof directions[number]; +type Direction = (typeof directions)[number]; const autocompleteData: Record> = { direction: directions.map((v) => ({ name: v, value: v })), 'depth strider': depthStriderLevels.map((n) => ({ name: `Depth Strider ${n}`, value: n })), version: mcVersions.map((v) => ({ name: v, value: v })), - design: allowedDesigns.map(([key, data]) => ({ name: data.name, value: key })), + design: allowedDesigns.map(([key, data]) => ({ name: data.name, value: key })), }; async function autocomplete(interaction: AutocompleteInteraction) { @@ -80,43 +80,36 @@ async function autocomplete(interaction: AutocompleteInteraction) { export default command; async function execute(interaction: ChatInputCommandInteraction, settings?: UserSettings) { - const versionRaw = interaction.options.getString('version', false)?.trim(); - const version = mcVersions.includes(versionRaw as Version) - ? (versionRaw as Version) - : undefined; - - const dsRaw = interaction.options.getString('depth_strider', false)?.trim(); - const dsLevel = depthStriderLevels.includes(Number(dsRaw) as DSLevel) - ? (Number(dsRaw) as DSLevel) - : undefined; - - const directionRaw = interaction.options.getString('direction', false)?.trim(); - const direction = directions.includes(directionRaw as Direction) - ? (directionRaw as Direction) - : undefined; - - const farm = farmsData[interaction.options.getString('design', true) as keyof typeof farmsData]; - - await interaction - .reply({ - content: `${calcSpeed(farm.speed.speed, farm.speed.soulSand, farm.speed.buildVersion, version, farm.speed.depthStrider, dsLevel)}`, - allowedMentions: { repliedUser: false }, - }) - .catch(() => undefined); + const versionRaw = interaction.options.getString('version', false)?.trim(); + const version = mcVersions.includes(versionRaw as Version) ? (versionRaw as Version) : undefined; + const dsRaw = interaction.options.getString('depth_strider', false)?.trim(); + const dsLevel = depthStriderLevels.includes(Number(dsRaw) as DSLevel) ? (Number(dsRaw) as DSLevel) : undefined; + + const directionRaw = interaction.options.getString('direction', false)?.trim(); + const direction = directions.includes(directionRaw as Direction) ? (directionRaw as Direction) : undefined; + + const farm = farmsData[interaction.options.getString('design', true) as keyof typeof farmsData]; + + await interaction + .reply({ + content: `${calcSpeed(farm.speed.speed, farm.speed.soulSand, farm.speed.buildVersion, version, farm.speed.depthStrider, dsLevel)}`, + allowedMentions: { repliedUser: false }, + }) + .catch(() => undefined); } async function calcSpeed( currentSpeed: number, usesSoulSand?: boolean, - designVersion?: "1.8.9" | "1.21", - targetVersion?: "1.8.9" | "1.21", + designVersion?: '1.8.9' | '1.21', + targetVersion?: '1.8.9' | '1.21', currentDepthStrider?: 1 | 2 | 3, targetDepthStrider?: 1 | 2 | 3, ): Promise { const versionMultiplier = { - "1.8.9": 0.4, - "1.21": 0.5, + '1.8.9': 0.4, + '1.21': 0.5, }; let speed = currentSpeed; diff --git a/src/commands/farm/temp.ts b/src/commands/farm/temp.ts index b97d7b5..3be549d 100644 --- a/src/commands/farm/temp.ts +++ b/src/commands/farm/temp.ts @@ -8,7 +8,7 @@ interface farmInfo { speed: number; depthStrider?: 1 | 2 | 3; soulSand: boolean; - buildVersion: "1.8.9" | "1.21" + buildVersion: '1.8.9' | '1.21'; method: 'straight' | 'running into wall' | 'angled into wall' | 'crouching'; }; angle: { @@ -37,7 +37,7 @@ export const farmsData: Record = { speed: { speed: 155, soulSand: false, - buildVersion: "1.8.9", + buildVersion: '1.8.9', method: 'straight', }, angle: { @@ -60,7 +60,7 @@ export const farmsData: Record = { speed: 400, depthStrider: 3, soulSand: true, - buildVersion: "1.8.9", + buildVersion: '1.8.9', method: 'running into wall', }, angle: { @@ -85,7 +85,7 @@ export const farmsData: Record = { speed: 400, depthStrider: 3, soulSand: true, - buildVersion: "1.8.9", + buildVersion: '1.8.9', method: 'running into wall', }, angle: { @@ -107,7 +107,7 @@ export const farmsData: Record = { speed: { speed: 365, soulSand: false, - buildVersion: "1.8.9", // todo: check + buildVersion: '1.8.9', // todo: check method: 'straight', // todo: check }, angle: { @@ -129,7 +129,7 @@ export const farmsData: Record = { speed: 93, depthStrider: 3, soulSand: false, - buildVersion: "1.8.9", + buildVersion: '1.8.9', method: 'straight', }, angle: { @@ -148,7 +148,7 @@ export const farmsData: Record = { speed: 347, depthStrider: 2, soulSand: true, - buildVersion: "1.8.9", + buildVersion: '1.8.9', method: 'running into wall', }, angle: { @@ -170,7 +170,7 @@ export const farmsData: Record = { speed: 328, depthStrider: 3, soulSand: false, - buildVersion: "1.8.9", + buildVersion: '1.8.9', method: 'angled into wall', }, angle: { @@ -196,7 +196,7 @@ export const farmsData: Record = { speed: 328, depthStrider: 3, soulSand: false, - buildVersion: "1.8.9", + buildVersion: '1.8.9', method: 'angled into wall', }, angle: { @@ -219,7 +219,7 @@ export const farmsData: Record = { speed: 347, depthStrider: 2, soulSand: true, - buildVersion: "1.8.9", + buildVersion: '1.8.9', method: 'running into wall', }, angle: { @@ -244,7 +244,7 @@ export const farmsData: Record = { speed: 347, depthStrider: 2, soulSand: true, - buildVersion: "1.8.9", + buildVersion: '1.8.9', method: 'running into wall', }, angle: { @@ -269,7 +269,7 @@ export const farmsData: Record = { speed: 233, depthStrider: 3, soulSand: true, - buildVersion: "1.8.9", + buildVersion: '1.8.9', method: 'angled into wall', }, angle: { @@ -292,7 +292,7 @@ export const farmsData: Record = { speed: { speed: 259, soulSand: false, - buildVersion: "1.8.9", + buildVersion: '1.8.9', method: 'angled into wall', }, angle: { @@ -313,7 +313,7 @@ export const farmsData: Record = { speed: 400, depthStrider: 3, soulSand: true, - buildVersion: "1.8.9", + buildVersion: '1.8.9', method: 'running into wall', }, angle: { @@ -336,7 +336,7 @@ export const farmsData: Record = { speed: { speed: 215, soulSand: false, - buildVersion: "1.8.9", + buildVersion: '1.8.9', method: 'running into wall', }, angle: { @@ -349,7 +349,9 @@ export const farmsData: Record = { garden: 'not_a_cowfr', }, authors: ['not a cow', 'Binrich'], - notes: ["Easier to build and use than regular cocoa, but wont work if you don't hold D (but doing so is better anyway so it doesn't really matter)"], + notes: [ + "Easier to build and use than regular cocoa, but wont work if you don't hold D (but doing so is better anyway so it doesn't really matter)", + ], }, blackCatCactus: { name: 'Black Cat Cactus', @@ -358,7 +360,7 @@ export const farmsData: Record = { speed: 464, depthStrider: 3, soulSand: false, - buildVersion: "1.8.9", + buildVersion: '1.8.9', method: 'straight', }, angle: { @@ -384,7 +386,7 @@ export const farmsData: Record = { speed: 464, depthStrider: 3, soulSand: false, - buildVersion: "1.8.9", + buildVersion: '1.8.9', method: 'straight', }, angle: { @@ -405,7 +407,7 @@ export const farmsData: Record = { speed: { speed: 328, soulSand: false, - buildVersion: "1.8.9", + buildVersion: '1.8.9', method: 'angled into wall', }, angle: { @@ -426,7 +428,7 @@ export const farmsData: Record = { speed: { speed: 328, soulSand: false, - buildVersion: "1.8.9", + buildVersion: '1.8.9', method: 'angled into wall', }, angle: { From 09c4bc6be4f61272b3ca4d4907a410636b0cc337 Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Thu, 22 May 2025 10:06:03 -0700 Subject: [PATCH 05/61] fix todo comment --- src/commands/farm/temp.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/farm/temp.ts b/src/commands/farm/temp.ts index 3be549d..e030a4c 100644 --- a/src/commands/farm/temp.ts +++ b/src/commands/farm/temp.ts @@ -106,8 +106,8 @@ export const farmsData: Record = { crops: [Crop.Melon, Crop.Pumpkin], speed: { speed: 365, - soulSand: false, - buildVersion: '1.8.9', // todo: check + soulSand: false, // todo: check + buildVersion: '1.8.9', method: 'straight', // todo: check }, angle: { From 0dcce95e87de4a5f9e179767d05b3330446df08b Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Thu, 22 May 2025 10:45:42 -0700 Subject: [PATCH 06/61] move stuff to npm package --- src/commands/farm/info.ts | 38 +-- src/commands/farm/temp.ts | 477 -------------------------------------- 2 files changed, 19 insertions(+), 496 deletions(-) delete mode 100644 src/commands/farm/temp.ts diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index 6b8974e..0da42ca 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -1,7 +1,16 @@ import { UserSettings } from 'api/elite.js'; import { CommandAccess, CommandType, EliteCommand, SlashCommandOptionType } from 'classes/commands/index.js'; import { AutocompleteInteraction, ChatInputCommandInteraction } from 'discord.js'; -import { farmsData } from './temp.js'; +import { + DepthStriderLevels, + Direction, + MinecraftVersion, + depthStriderLevels, + directions, + farmDesigns, + farmsData, + mcVersions, +} from 'farming-weight'; const command = new EliteCommand({ name: 'info', @@ -45,22 +54,11 @@ const command = new EliteCommand({ execute: execute, }); -export const allowedDesigns = Object.entries(farmsData); - -const mcVersions = ['1.8.9', '1.21'] as const; -type Version = (typeof mcVersions)[number]; - -const depthStriderLevels = [1, 2, 3] as const; -type DSLevel = (typeof depthStriderLevels)[number]; - -const directions = ['North', 'South', 'East', 'West'] as const; -type Direction = (typeof directions)[number]; - const autocompleteData: Record> = { direction: directions.map((v) => ({ name: v, value: v })), 'depth strider': depthStriderLevels.map((n) => ({ name: `Depth Strider ${n}`, value: n })), version: mcVersions.map((v) => ({ name: v, value: v })), - design: allowedDesigns.map(([key, data]) => ({ name: data.name, value: key })), + design: farmDesigns.map(([key, data]) => ({ name: data.name, value: key })), }; async function autocomplete(interaction: AutocompleteInteraction) { @@ -81,10 +79,12 @@ export default command; async function execute(interaction: ChatInputCommandInteraction, settings?: UserSettings) { const versionRaw = interaction.options.getString('version', false)?.trim(); - const version = mcVersions.includes(versionRaw as Version) ? (versionRaw as Version) : undefined; + const version = mcVersions.includes(versionRaw as MinecraftVersion) ? (versionRaw as MinecraftVersion) : undefined; const dsRaw = interaction.options.getString('depth_strider', false)?.trim(); - const dsLevel = depthStriderLevels.includes(Number(dsRaw) as DSLevel) ? (Number(dsRaw) as DSLevel) : undefined; + const dsLevel = depthStriderLevels.includes(Number(dsRaw) as DepthStriderLevels) + ? (Number(dsRaw) as DepthStriderLevels) + : undefined; const directionRaw = interaction.options.getString('direction', false)?.trim(); const direction = directions.includes(directionRaw as Direction) ? (directionRaw as Direction) : undefined; @@ -102,10 +102,10 @@ async function execute(interaction: ChatInputCommandInteraction, settings?: User async function calcSpeed( currentSpeed: number, usesSoulSand?: boolean, - designVersion?: '1.8.9' | '1.21', - targetVersion?: '1.8.9' | '1.21', - currentDepthStrider?: 1 | 2 | 3, - targetDepthStrider?: 1 | 2 | 3, + designVersion?: MinecraftVersion, + targetVersion?: MinecraftVersion, + currentDepthStrider?: DepthStriderLevels, + targetDepthStrider?: DepthStriderLevels, ): Promise { const versionMultiplier = { '1.8.9': 0.4, diff --git a/src/commands/farm/temp.ts b/src/commands/farm/temp.ts deleted file mode 100644 index e030a4c..0000000 --- a/src/commands/farm/temp.ts +++ /dev/null @@ -1,477 +0,0 @@ -import { Crop } from 'farming-weight'; - -interface farmInfo { - name: string; - description?: string; - crops: Crop[]; - speed: { - speed: number; - depthStrider?: 1 | 2 | 3; - soulSand: boolean; - buildVersion: '1.8.9' | '1.21'; - method: 'straight' | 'running into wall' | 'angled into wall' | 'crouching'; - }; - angle: { - yaw: number; - pitch: number; - }; - bps: number; - laneDepth: number; - tutorials?: { - thread?: string; - video?: string; - garden?: string; - schematic?: string; - }; - authors?: string[]; - replacedBy?: string[]; - notes?: string[]; -} - -const blackCatNote = 'Despite the name, this farm **does not** use a black cat pet anymore'; - -export const farmsData: Record = { - idkdomPumpkin: { - name: 'IdkDom Melon/Pumpkin', - crops: [Crop.Melon, Crop.Pumpkin], - speed: { - speed: 155, - soulSand: false, - buildVersion: '1.8.9', - method: 'straight', - }, - angle: { - yaw: 0, - pitch: 28.5, - }, - bps: 19.5, - laneDepth: 3, - tutorials: { - video: 'https://www.youtube.com/watch?v=Zy_w332uUic', - garden: 'IdkDom', - }, - authors: ['IdkDom'], - replacedBy: ['easierMelon', 'chisslMelon'], - }, - blackCatMelon: { - name: 'SunTzu & MelonKingDe Black Cat Melon', - crops: [Crop.Melon, Crop.Pumpkin], - speed: { - speed: 400, - depthStrider: 3, - soulSand: true, - buildVersion: '1.8.9', - method: 'running into wall', - }, - angle: { - yaw: 0, - pitch: -59, - }, - bps: 19.8, - laneDepth: 3, - tutorials: { - thread: 'https://discord.com/channels/1096051612373487687/1159960881287942234', - video: 'https://www.youtube.com/watch?v=5k9c7qK0l58', - garden: 'MelonKingDe', - }, - authors: ['AgitatedSnake92', 'MelonKingDe', 'SunTzu101'], - replacedBy: ['easierMelon', 'chisslMelon'], - notes: [blackCatNote], - }, - easierMelon: { - name: 'Easier to Build Melon/Pumpkin', - crops: [Crop.Melon, Crop.Pumpkin], - speed: { - speed: 400, - depthStrider: 3, - soulSand: true, - buildVersion: '1.8.9', - method: 'running into wall', - }, - angle: { - yaw: 0, - pitch: -59, - }, - bps: 19.8, - laneDepth: 3, - tutorials: { - thread: 'https://discord.com/channels/1096051612373487687/1358514959247741068', - video: 'https://www.youtube.com/watch?v=s4HV0RyWcoI', - garden: 'IdkVenom', - }, - authors: ['AgitatedSnake92', 'MelonKingDe', 'IdkVenom', 'DeadlyIPanda'], - }, - chisslMelon: { - name: 'Chissl Waterless Melon/Pumpkin', - crops: [Crop.Melon, Crop.Pumpkin], - speed: { - speed: 365, - soulSand: false, // todo: check - buildVersion: '1.8.9', - method: 'straight', // todo: check - }, - angle: { - yaw: 0, - pitch: 59, - }, - bps: 19.9, - laneDepth: 3, - tutorials: { - garden: 'Chissl', - }, - authors: ['AgitatedSnake92', 'Chissl'], - notes: ['Very difficult and time consuming to build, only worthwhile for extreme farmers'], - }, - dropdownWheat: { - name: 'Dropdown Wheat/Potato/Carrot/Netherwart', - crops: [Crop.Wheat, Crop.Potato, Crop.Carrot, Crop.NetherWart], - speed: { - speed: 93, - depthStrider: 3, - soulSand: false, - buildVersion: '1.8.9', - method: 'straight', - }, - angle: { - yaw: 0, - pitch: 3, - }, - bps: 19.8, - laneDepth: 5, - replacedBy: ['aceWheat', 'draipWheat', 'z109Wheat'], - notes: ['Annoying to use', 'Not infinite even at garden 15', 'Requires 5 plots, no less'], - }, - aceWheat: { - name: 'Ace Wheat/Potato/Carrot/Netherwart', - crops: [Crop.Wheat, Crop.Potato, Crop.Carrot, Crop.NetherWart], - speed: { - speed: 347, - depthStrider: 2, - soulSand: true, - buildVersion: '1.8.9', - method: 'running into wall', - }, - angle: { - yaw: 0, - pitch: 3, - }, - bps: 20, - laneDepth: 5, - tutorials: { - video: 'https://www.youtube.com/watch?v=hz4lGUz0JP4', - garden: 'SageUk', - }, - authors: ['AgitatedSnake92'], - }, - draipWheat: { - name: 'Draip Looping Wheat/Potato/Carrot/Netherwart', - crops: [Crop.Wheat, Crop.Potato, Crop.Carrot, Crop.NetherWart], - speed: { - speed: 328, - depthStrider: 3, - soulSand: false, - buildVersion: '1.8.9', - method: 'angled into wall', - }, - angle: { - yaw: 45, - pitch: 3, - }, - bps: 20, - laneDepth: 3, - tutorials: { - thread: 'https://discord.com/channels/1096051612373487687/1159965565218201721', - video: 'https://www.youtube.com/watch?v=gcJ5U7SyA-c', - }, - authors: ['Draip'], - notes: [ - 'Nice for pest farming because it loops, but it doesn require more plots than other designs', - 'Lanes can be as deep as you want, deeper means laneswitches are easier', - ], - }, - z109Wheat: { - name: 'Z109 Sprial Wheat/Potato/Carrot/Netherwart', - crops: [Crop.Wheat, Crop.Potato, Crop.Carrot, Crop.NetherWart], - speed: { - speed: 328, - depthStrider: 3, - soulSand: false, - buildVersion: '1.8.9', - method: 'angled into wall', - }, - angle: { - yaw: 45, - pitch: 3, - }, - bps: 20, - laneDepth: 3, - tutorials: { - thread: 'https://discord.com/channels/1096051612373487687/1253213095984365629', - video: 'https://www.youtube.com/watch?v=9yVNsafjOCA', - garden: 'Z109', - }, - authors: ['AgitatedSnake92', 'Z109'], - }, - blackCatWheat: { - name: 'Black Cat Wheat/Potato/Carrot', - crops: [Crop.Wheat, Crop.Potato, Crop.Carrot], - speed: { - speed: 347, - depthStrider: 2, - soulSand: true, - buildVersion: '1.8.9', - method: 'running into wall', - }, - angle: { - yaw: 0, - pitch: 3, - }, - bps: 19.9, - laneDepth: 5, - tutorials: { - thread: 'https://discord.com/channels/1096051612373487687/1159961248545374290', - video: 'https://www.youtube.com/watch?v=KBGIuETQI-g', - garden: 'MelonKingDe', - }, - authors: ['AgitatedSnake92', 'MelonKingDe', 'SunTzu101'], - replacedBy: ['aceWheat', 'draipWheat', 'z109Wheat'], - notes: [blackCatNote], - }, - blackCatNetherwart: { - name: 'Black Cat Nether Wart', - crops: [Crop.NetherWart], - speed: { - speed: 347, - depthStrider: 2, - soulSand: true, - buildVersion: '1.8.9', - method: 'running into wall', - }, - angle: { - yaw: 0, - pitch: 3, - }, - bps: 19.9, - laneDepth: 5, - tutorials: { - thread: 'https://discord.com/channels/1096051612373487687/1159961642952556636', - video: 'https://www.youtube.com/watch?v=n218KDmL-5s', - garden: 'MelonKingDe', - }, - authors: ['AgitatedSnake92', 'MelonKingDe', 'SunTzu101'], - replacedBy: ['aceWheat', 'draipWheat', 'z109Wheat'], - notes: [blackCatNote], - }, - sdsMushroom: { - name: 'Slanted Downward Spiral (SDS) Mushroom', - crops: [Crop.Mushroom], - speed: { - speed: 233, - depthStrider: 3, - soulSand: true, - buildVersion: '1.8.9', - method: 'angled into wall', - }, - angle: { - yaw: 16, - pitch: 5.5, - }, - bps: 19.7, - laneDepth: 4, - tutorials: { - thread: 'https://discord.com/channels/1096051612373487687/1159960305300930631', - video: 'https://www.youtube.com/watch?v=QyWf0DO831g', - garden: 'MelonKingDe', - }, - authors: ['AgitatedSnake92', 'MelonKingDe', 'SunTzu101'], - replacedBy: ['idkpoisonMushroom'], - }, - idkpoisonMushroom: { - name: 'IdkPoison_ Mushroom', - crops: [Crop.Mushroom], - speed: { - speed: 259, - soulSand: false, - buildVersion: '1.8.9', - method: 'angled into wall', - }, - angle: { - yaw: 0, // todo: fix - pitch: 0, - }, - bps: 19.9, - laneDepth: 4, - tutorials: { - garden: 'IdkPoison_', - }, - authors: ['AgitatedSnake92', 'IdkPoison_'], - }, - blackCatCocoa: { - name: 'Black Cat Cocoa', - crops: [Crop.CocoaBeans], - speed: { - speed: 400, - depthStrider: 3, - soulSand: true, - buildVersion: '1.8.9', - method: 'running into wall', - }, - angle: { - yaw: 0, - pitch: -45, - }, - bps: 19.98, - laneDepth: 3, - tutorials: { - thread: 'https://discord.com/channels/1096051612373487687/1159959995329298443', - video: 'https://www.youtube.com/watch?v=WWR2duiwxK4', - garden: 'FarmingHub', - }, - authors: ['AgitatedSnake92'], - notes: [blackCatNote], - }, - singleLaneCocoa: { - name: 'Single Lane Cocoa', - crops: [Crop.CocoaBeans], - speed: { - speed: 215, - soulSand: false, - buildVersion: '1.8.9', - method: 'running into wall', - }, - angle: { - yaw: 0, - pitch: -45, - }, - bps: 19.97, - laneDepth: 3, - tutorials: { - garden: 'not_a_cowfr', - }, - authors: ['not a cow', 'Binrich'], - notes: [ - "Easier to build and use than regular cocoa, but wont work if you don't hold D (but doing so is better anyway so it doesn't really matter)", - ], - }, - blackCatCactus: { - name: 'Black Cat Cactus', - crops: [Crop.Cactus], - speed: { - speed: 464, - depthStrider: 3, - soulSand: false, - buildVersion: '1.8.9', - method: 'straight', - }, - angle: { - yaw: 0, - pitch: 0, - }, - bps: 19.9, - laneDepth: 1, - tutorials: { - thread: 'https://discord.com/channels/1096051612373487687/1159959766748119050', - video: 'https://www.youtube.com/watch?v=Kj7qxeq1jEw', - garden: 'MelonKingDe', - }, - authors: ['AgitatedSnake92', 'MelonKingDe', 'SunTzu101'], - notes: [ - 'Despite the name, this farm **does not** use a black cat pet anymore, instead, cactus knife raises speed cap now', - ], - }, - aceCactus: { - name: 'Ace Cactus', - crops: [Crop.Cactus], - speed: { - speed: 464, - depthStrider: 3, - soulSand: false, - buildVersion: '1.8.9', - method: 'straight', - }, - angle: { - yaw: 0, - pitch: 0, - }, - bps: 19.9, - laneDepth: 1, - tutorials: { - garden: 'LunaSappho', - }, - authors: ['AgitatedSnake92'], - notes: ["Don't worry about getting over 400 speed, cactus knife raises speed cap by 100"], - }, - regularCane: { - name: 'Regular Sugar Cane', - crops: [Crop.SugarCane], - speed: { - speed: 328, - soulSand: false, - buildVersion: '1.8.9', - method: 'angled into wall', - }, - angle: { - yaw: 45, - pitch: 0, - }, - bps: 19.98, - laneDepth: 2, - tutorials: { - thread: 'https://discord.com/channels/1096051612373487687/1159960545487761479', - video: 'https://www.youtube.com/watch?v=nQ5yjQU9gmo', - garden: 'MelonKingDe', - }, - }, - farminghubCane: { - name: 'FarmingHub Sugar Cane', - crops: [Crop.SugarCane], - speed: { - speed: 328, - soulSand: false, - buildVersion: '1.8.9', - method: 'angled into wall', - }, - angle: { - yaw: 45, - pitch: 0, - }, - bps: 20, - laneDepth: 2, - tutorials: { - garden: 'FarmingHub', - }, - authors: ['AgitatedSnake92'], - }, -}; - -// designs -// ✅=done ❌=not done yet - -// sds mush ✅ -// idkpoison mush ✅ - -// draip wheat ✅ -// ace wheat (sageuk as garden?) ✅ -// z109 wheat ✅ -// clovis' wierd ass dropdown design ❌ -// black cat wheat ✅ - -// black cat netherwart ✅ - -// cow cocoa ✅ -// farminghub cocoa ✅ - -// ace cactus (visi luna) ✅ -// regular cactus ❌ -// black cat cactus ✅ - -// regular cane, link melonking vid ✅ -// farminghub cane ✅ - -// maybe have farm info contain which keys always held and which keys alernate between - -// maybe clac method used via things like -// 0 yaw = straight -// non 0 yaw = angled into wall -// 0 yaw and movement key si always held = running into wall -// idk how it would work for like draip and z109 though, maybe not a good idea then From 06c4a37ab3795bff29dc7b99e57006aee4970b5b Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Thu, 22 May 2025 10:56:57 -0700 Subject: [PATCH 07/61] crop autocomplete --- src/autocomplete/crops.ts | 26 ++++++++++++++++++++++++++ src/commands/farm/search.ts | 8 ++------ 2 files changed, 28 insertions(+), 6 deletions(-) create mode 100644 src/autocomplete/crops.ts diff --git a/src/autocomplete/crops.ts b/src/autocomplete/crops.ts new file mode 100644 index 0000000..a4df7a5 --- /dev/null +++ b/src/autocomplete/crops.ts @@ -0,0 +1,26 @@ +import { EliteSlashCommandOption, SlashCommandOptionType } from "classes/commands/options.js"; +import { CROP_ARRAY } from "classes/Util.js"; +import { AutocompleteInteraction } from "discord.js"; +import { Crop, getCropDisplayName } from "farming-weight"; + +export const eliteCropOption: EliteSlashCommandOption = { + name: 'crop', + description: 'The crop to get results for.', + type: SlashCommandOptionType.String, + required: true, + autocomplete, +}; + +export async function autocomplete(interaction: AutocompleteInteraction) { + if (interaction.responded) return; + + const option = interaction.options.getFocused(true); + const options = CROP_ARRAY.map((v) => ({ name: getCropDisplayName(v), value: v })); + if (!options) return; + + const input = option.value.toLowerCase(); + + const filtered = options.filter((opt) => opt.name.toLowerCase().startsWith(input)); + + await interaction.respond(filtered); +} diff --git a/src/commands/farm/search.ts b/src/commands/farm/search.ts index 2b77b82..e268085 100644 --- a/src/commands/farm/search.ts +++ b/src/commands/farm/search.ts @@ -1,4 +1,5 @@ import { UserSettings } from 'api/elite.js'; +import { eliteCropOption } from 'autocomplete/crops.js'; import { CommandAccess, CommandType, EliteCommand, SlashCommandOptionType } from 'classes/commands/index.js'; import { AutocompleteInteraction, ChatInputCommandInteraction } from 'discord.js'; @@ -9,12 +10,7 @@ const command = new EliteCommand({ type: CommandType.Slash, subCommand: true, options: { - design: { - name: 'crop', - description: 'Search for a farm design!', - type: SlashCommandOptionType.String, - required: true, - }, + crop: eliteCropOption, }, execute: execute, }); From 8de8d1c6939c17235a289ea11db7b4ac2900bdb7 Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Thu, 22 May 2025 11:04:48 -0700 Subject: [PATCH 08/61] fix search command --- src/commands/farm/search.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/farm/search.ts b/src/commands/farm/search.ts index e268085..0e82f9b 100644 --- a/src/commands/farm/search.ts +++ b/src/commands/farm/search.ts @@ -4,7 +4,7 @@ import { CommandAccess, CommandType, EliteCommand, SlashCommandOptionType } from import { AutocompleteInteraction, ChatInputCommandInteraction } from 'discord.js'; const command = new EliteCommand({ - name: 'info', + name: 'search', description: 'Get info about a farm design!', access: CommandAccess.Everywhere, type: CommandType.Slash, From f9f4a2cef372488e2badfd99162aac5a6e82894c Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Thu, 22 May 2025 11:37:50 -0700 Subject: [PATCH 09/61] use components instead of params --- src/autocomplete/crops.ts | 32 +++++------ src/commands/farm/info.ts | 115 ++++++++++++++++++++------------------ 2 files changed, 76 insertions(+), 71 deletions(-) diff --git a/src/autocomplete/crops.ts b/src/autocomplete/crops.ts index a4df7a5..4eb2e5a 100644 --- a/src/autocomplete/crops.ts +++ b/src/autocomplete/crops.ts @@ -1,26 +1,26 @@ -import { EliteSlashCommandOption, SlashCommandOptionType } from "classes/commands/options.js"; -import { CROP_ARRAY } from "classes/Util.js"; -import { AutocompleteInteraction } from "discord.js"; -import { Crop, getCropDisplayName } from "farming-weight"; +import { CROP_ARRAY } from 'classes/Util.js'; +import { EliteSlashCommandOption, SlashCommandOptionType } from 'classes/commands/options.js'; +import { AutocompleteInteraction } from 'discord.js'; +import { Crop, getCropDisplayName } from 'farming-weight'; export const eliteCropOption: EliteSlashCommandOption = { - name: 'crop', - description: 'The crop to get results for.', - type: SlashCommandOptionType.String, - required: true, - autocomplete, + name: 'crop', + description: 'The crop to get results for.', + type: SlashCommandOptionType.String, + required: true, + autocomplete, }; export async function autocomplete(interaction: AutocompleteInteraction) { - if (interaction.responded) return; + if (interaction.responded) return; - const option = interaction.options.getFocused(true); - const options = CROP_ARRAY.map((v) => ({ name: getCropDisplayName(v), value: v })); - if (!options) return; + const option = interaction.options.getFocused(true); + const options = CROP_ARRAY.map((v) => ({ name: getCropDisplayName(v), value: v })); + if (!options) return; - const input = option.value.toLowerCase(); + const input = option.value.toLowerCase(); - const filtered = options.filter((opt) => opt.name.toLowerCase().startsWith(input)); + const filtered = options.filter((opt) => opt.name.toLowerCase().startsWith(input)); - await interaction.respond(filtered); + await interaction.respond(filtered); } diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index 0da42ca..154b30e 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -1,16 +1,18 @@ import { UserSettings } from 'api/elite.js'; import { CommandAccess, CommandType, EliteCommand, SlashCommandOptionType } from 'classes/commands/index.js'; -import { AutocompleteInteraction, ChatInputCommandInteraction } from 'discord.js'; import { - DepthStriderLevels, - Direction, - MinecraftVersion, - depthStriderLevels, - directions, - farmDesigns, - farmsData, - mcVersions, -} from 'farming-weight'; + ActionRowBuilder, + AutocompleteInteraction, + ButtonBuilder, + ButtonStyle, + ChatInputCommandInteraction, + ContainerBuilder, + MessageActionRowComponentBuilder, + StringSelectMenuBuilder, + StringSelectMenuOptionBuilder, + TextDisplayBuilder, +} from 'discord.js'; +import { DepthStriderLevels, MinecraftVersion, farmDesigns } from 'farming-weight'; const command = new EliteCommand({ name: 'info', @@ -24,48 +26,17 @@ const command = new EliteCommand({ description: 'Select a farm design!', type: SlashCommandOptionType.String, required: true, - }, - direction: { - name: 'direction', - description: 'Optionally select the direction you face when farming, this helps to show the correct angles.', - type: SlashCommandOptionType.String, autocomplete: autocomplete, }, - // maybe just put both possible yaws for farms that this would affect? this would probably just be confusing for most people - flipped: { - name: 'flipped', - description: - 'Optionally select whether or not you flipped (mirrored) the original design, this helps to show the correct angles.', - type: SlashCommandOptionType.String, - autocomplete: autocomplete, - }, - depth_strider: { - name: 'depth strider', - description: 'Optionally select the depth strider level you use, this helps to show the correct speed.', - type: SlashCommandOptionType.String, - }, - version: { - name: 'version', - description: - 'Optionally select the Minecraft version you play on, this helps to show the correct speed for farms that use soul sand.', - type: SlashCommandOptionType.String, - }, }, execute: execute, }); -const autocompleteData: Record> = { - direction: directions.map((v) => ({ name: v, value: v })), - 'depth strider': depthStriderLevels.map((n) => ({ name: `Depth Strider ${n}`, value: n })), - version: mcVersions.map((v) => ({ name: v, value: v })), - design: farmDesigns.map(([key, data]) => ({ name: data.name, value: key })), -}; - async function autocomplete(interaction: AutocompleteInteraction) { if (interaction.responded) return; const option = interaction.options.getFocused(true); - const options = autocompleteData[option.name]; + const options = farmDesigns.map(([key, data]) => ({ name: data.name, value: key })); if (!options) return; const input = option.value.toLowerCase(); @@ -78,22 +49,56 @@ async function autocomplete(interaction: AutocompleteInteraction) { export default command; async function execute(interaction: ChatInputCommandInteraction, settings?: UserSettings) { - const versionRaw = interaction.options.getString('version', false)?.trim(); - const version = mcVersions.includes(versionRaw as MinecraftVersion) ? (versionRaw as MinecraftVersion) : undefined; - - const dsRaw = interaction.options.getString('depth_strider', false)?.trim(); - const dsLevel = depthStriderLevels.includes(Number(dsRaw) as DepthStriderLevels) - ? (Number(dsRaw) as DepthStriderLevels) - : undefined; - - const directionRaw = interaction.options.getString('direction', false)?.trim(); - const direction = directions.includes(directionRaw as Direction) ? (directionRaw as Direction) : undefined; - - const farm = farmsData[interaction.options.getString('design', true) as keyof typeof farmsData]; + const components = [ + new ContainerBuilder().addTextDisplayComponents(new TextDisplayBuilder().setContent('stuff goes here')), + new ContainerBuilder() + .addTextDisplayComponents(new TextDisplayBuilder().setContent('Settings')) + .addActionRowComponents( + new ActionRowBuilder().addComponents( + new StringSelectMenuBuilder() + .setCustomId('depth_strider') + .setPlaceholder('Select the depth strider level you use') + .addOptions( + new StringSelectMenuOptionBuilder().setLabel('Depth Strider 1').setValue('1'), + new StringSelectMenuOptionBuilder().setLabel('Depth Strider 2').setValue('2'), + new StringSelectMenuOptionBuilder().setLabel('Depth Strider 3').setValue('3'), + ), + ), + ) + .addActionRowComponents( + new ActionRowBuilder().addComponents( + new StringSelectMenuBuilder() + .setCustomId('direction') + .setPlaceholder('Select the direction your farm faces') + .addOptions( + new StringSelectMenuOptionBuilder().setLabel('North').setValue('North'), + new StringSelectMenuOptionBuilder().setLabel('South').setValue('South'), + new StringSelectMenuOptionBuilder().setLabel('East').setValue('East'), + new StringSelectMenuOptionBuilder().setLabel('West').setValue('West'), + ), + ), + ) + .addActionRowComponents( + new ActionRowBuilder().addComponents( + new StringSelectMenuBuilder() + .setCustomId('version') + .setPlaceholder('Select Minecaft version') + .addOptions( + new StringSelectMenuOptionBuilder().setLabel('1.8.9').setValue('1.8.9'), + new StringSelectMenuOptionBuilder().setLabel('1.21').setValue('1.21'), + ), + ), + ) + .addActionRowComponents( + new ActionRowBuilder().addComponents( + new ButtonBuilder().setStyle(ButtonStyle.Secondary).setLabel('Remember my choices').setCustomId('save'), + ), + ), + ]; await interaction .reply({ - content: `${calcSpeed(farm.speed.speed, farm.speed.soulSand, farm.speed.buildVersion, version, farm.speed.depthStrider, dsLevel)}`, + components: components, allowedMentions: { repliedUser: false }, }) .catch(() => undefined); From e635042d7fedf47b35747a4a0d19d35cd55b635e Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Thu, 22 May 2025 11:38:43 -0700 Subject: [PATCH 10/61] remove unused import --- src/autocomplete/crops.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/autocomplete/crops.ts b/src/autocomplete/crops.ts index 4eb2e5a..b1c9120 100644 --- a/src/autocomplete/crops.ts +++ b/src/autocomplete/crops.ts @@ -1,7 +1,7 @@ import { CROP_ARRAY } from 'classes/Util.js'; import { EliteSlashCommandOption, SlashCommandOptionType } from 'classes/commands/options.js'; import { AutocompleteInteraction } from 'discord.js'; -import { Crop, getCropDisplayName } from 'farming-weight'; +import { getCropDisplayName } from 'farming-weight'; export const eliteCropOption: EliteSlashCommandOption = { name: 'crop', From 9a8c847a29ea76d92e490501a8e171af8da30a02 Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Thu, 22 May 2025 13:58:17 -0700 Subject: [PATCH 11/61] add main content embed --- src/commands/farm/info.ts | 40 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index 154b30e..cd779b4 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -8,11 +8,14 @@ import { ChatInputCommandInteraction, ContainerBuilder, MessageActionRowComponentBuilder, + SeparatorBuilder, + SeparatorSpacingSize, StringSelectMenuBuilder, StringSelectMenuOptionBuilder, TextDisplayBuilder, } from 'discord.js'; -import { DepthStriderLevels, MinecraftVersion, farmDesigns } from 'farming-weight'; +import { DepthStriderLevels, Direction, MinecraftVersion, farmDesigns, farmsData } from 'farming-weight'; +import { $ZodAny } from 'zod/v4/core'; const command = new EliteCommand({ name: 'info', @@ -49,10 +52,41 @@ async function autocomplete(interaction: AutocompleteInteraction) { export default command; async function execute(interaction: ChatInputCommandInteraction, settings?: UserSettings) { + let design = farmsData.chisslMelon; + let depthStriderLevel = 1 as DepthStriderLevels; + let orienation = "North" as Direction; + let version = "1.8.9" as MinecraftVersion; + const components = [ - new ContainerBuilder().addTextDisplayComponents(new TextDisplayBuilder().setContent('stuff goes here')), new ContainerBuilder() - .addTextDisplayComponents(new TextDisplayBuilder().setContent('Settings')) + .addTextDisplayComponents( + new TextDisplayBuilder().setContent(`# ${design.name}`), + ) + .addTextDisplayComponents( + new TextDisplayBuilder().setContent(`Yaw: ${design.angle.yaw}, Pitch: ${design.angle.pitch}\nSpeed: ${design.speed.speed}, Depth strider level: ${depthStriderLevel}`), + ) + .addSeparatorComponents( + new SeparatorBuilder().setSpacing(SeparatorSpacingSize.Small).setDivider(true), + ) + .addTextDisplayComponents( + new TextDisplayBuilder().setContent(`bps: ${design.bps}\nLane time: \nKeys used: `), + ) + .addSeparatorComponents( + new SeparatorBuilder().setSpacing(SeparatorSpacingSize.Small).setDivider(true), + ) + .addTextDisplayComponents( + // todo: dont have field/value if there isnt an example + new TextDisplayBuilder().setContent(`Tutorial video: ${design.tutorials?.video ?? 'n/a'}\nDiscussion thread: ${design.tutorials?.thread ?? 'n/a'}\nVisitable example: ${design.tutorials?.garden ?? 'n/a'}`), + ) + .addSeparatorComponents( + new SeparatorBuilder().setSpacing(SeparatorSpacingSize.Small).setDivider(true), + ) + .addTextDisplayComponents( + // todo: dont have field if there isnt any authors + new TextDisplayBuilder().setContent(`-# Authors: ${design.authors?.join(", ") ?? 'n/a'}`), + ), + new ContainerBuilder() + .addTextDisplayComponents(new TextDisplayBuilder().setContent('# Settings')) .addActionRowComponents( new ActionRowBuilder().addComponents( new StringSelectMenuBuilder() From ac5623f50945b839fff369dcccdd90a64f6d1f4a Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Thu, 22 May 2025 14:02:10 -0700 Subject: [PATCH 12/61] sepereate the 2 components --- src/commands/farm/info.ts | 143 +++++++++++++++++++------------------- 1 file changed, 71 insertions(+), 72 deletions(-) diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index cd779b4..ab490e3 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -57,82 +57,81 @@ async function execute(interaction: ChatInputCommandInteraction, settings?: User let orienation = "North" as Direction; let version = "1.8.9" as MinecraftVersion; - const components = [ - new ContainerBuilder() - .addTextDisplayComponents( - new TextDisplayBuilder().setContent(`# ${design.name}`), - ) - .addTextDisplayComponents( - new TextDisplayBuilder().setContent(`Yaw: ${design.angle.yaw}, Pitch: ${design.angle.pitch}\nSpeed: ${design.speed.speed}, Depth strider level: ${depthStriderLevel}`), - ) - .addSeparatorComponents( - new SeparatorBuilder().setSpacing(SeparatorSpacingSize.Small).setDivider(true), - ) - .addTextDisplayComponents( - new TextDisplayBuilder().setContent(`bps: ${design.bps}\nLane time: \nKeys used: `), - ) - .addSeparatorComponents( - new SeparatorBuilder().setSpacing(SeparatorSpacingSize.Small).setDivider(true), - ) - .addTextDisplayComponents( - // todo: dont have field/value if there isnt an example - new TextDisplayBuilder().setContent(`Tutorial video: ${design.tutorials?.video ?? 'n/a'}\nDiscussion thread: ${design.tutorials?.thread ?? 'n/a'}\nVisitable example: ${design.tutorials?.garden ?? 'n/a'}`), - ) - .addSeparatorComponents( - new SeparatorBuilder().setSpacing(SeparatorSpacingSize.Small).setDivider(true), - ) - .addTextDisplayComponents( - // todo: dont have field if there isnt any authors - new TextDisplayBuilder().setContent(`-# Authors: ${design.authors?.join(", ") ?? 'n/a'}`), - ), - new ContainerBuilder() - .addTextDisplayComponents(new TextDisplayBuilder().setContent('# Settings')) - .addActionRowComponents( - new ActionRowBuilder().addComponents( - new StringSelectMenuBuilder() - .setCustomId('depth_strider') - .setPlaceholder('Select the depth strider level you use') - .addOptions( - new StringSelectMenuOptionBuilder().setLabel('Depth Strider 1').setValue('1'), - new StringSelectMenuOptionBuilder().setLabel('Depth Strider 2').setValue('2'), - new StringSelectMenuOptionBuilder().setLabel('Depth Strider 3').setValue('3'), - ), - ), - ) - .addActionRowComponents( - new ActionRowBuilder().addComponents( - new StringSelectMenuBuilder() - .setCustomId('direction') - .setPlaceholder('Select the direction your farm faces') - .addOptions( - new StringSelectMenuOptionBuilder().setLabel('North').setValue('North'), - new StringSelectMenuOptionBuilder().setLabel('South').setValue('South'), - new StringSelectMenuOptionBuilder().setLabel('East').setValue('East'), - new StringSelectMenuOptionBuilder().setLabel('West').setValue('West'), - ), - ), - ) - .addActionRowComponents( - new ActionRowBuilder().addComponents( - new StringSelectMenuBuilder() - .setCustomId('version') - .setPlaceholder('Select Minecaft version') - .addOptions( - new StringSelectMenuOptionBuilder().setLabel('1.8.9').setValue('1.8.9'), - new StringSelectMenuOptionBuilder().setLabel('1.21').setValue('1.21'), - ), - ), - ) - .addActionRowComponents( - new ActionRowBuilder().addComponents( - new ButtonBuilder().setStyle(ButtonStyle.Secondary).setLabel('Remember my choices').setCustomId('save'), - ), + let farmInfoComponent = new ContainerBuilder() + .addTextDisplayComponents( + new TextDisplayBuilder().setContent(`# ${design.name}`), + ) + .addTextDisplayComponents( + new TextDisplayBuilder().setContent(`Yaw: ${design.angle.yaw}, Pitch: ${design.angle.pitch}\nSpeed: ${design.speed.speed}, Depth strider level: ${depthStriderLevel}`), + ) + .addSeparatorComponents( + new SeparatorBuilder().setSpacing(SeparatorSpacingSize.Small).setDivider(true), + ) + .addTextDisplayComponents( + new TextDisplayBuilder().setContent(`bps: ${design.bps}\nLane time: \nKeys used: `), + ) + .addSeparatorComponents( + new SeparatorBuilder().setSpacing(SeparatorSpacingSize.Small).setDivider(true), + ) + .addTextDisplayComponents( + // todo: dont have field/value if there isnt an example + new TextDisplayBuilder().setContent(`Tutorial video: ${design.tutorials?.video ?? 'n/a'}\nDiscussion thread: ${design.tutorials?.thread ?? 'n/a'}\nVisitable example: ${design.tutorials?.garden ?? 'n/a'}`), + ) + .addSeparatorComponents( + new SeparatorBuilder().setSpacing(SeparatorSpacingSize.Small).setDivider(true), + ) + .addTextDisplayComponents( + // todo: dont have field if there isnt any authors + new TextDisplayBuilder().setContent(`-# Authors: ${design.authors?.join(", ") ?? 'n/a'}`), + ); + + const settingsComponent = new ContainerBuilder() + .addTextDisplayComponents(new TextDisplayBuilder().setContent('# Settings')) + .addActionRowComponents( + new ActionRowBuilder().addComponents( + new StringSelectMenuBuilder() + .setCustomId('depth_strider') + .setPlaceholder('Select the depth strider level you use') + .addOptions( + new StringSelectMenuOptionBuilder().setLabel('Depth Strider 1').setValue('1'), + new StringSelectMenuOptionBuilder().setLabel('Depth Strider 2').setValue('2'), + new StringSelectMenuOptionBuilder().setLabel('Depth Strider 3').setValue('3'), + ), + ), + ) + .addActionRowComponents( + new ActionRowBuilder().addComponents( + new StringSelectMenuBuilder() + .setCustomId('direction') + .setPlaceholder('Select the direction your farm faces') + .addOptions( + new StringSelectMenuOptionBuilder().setLabel('North').setValue('North'), + new StringSelectMenuOptionBuilder().setLabel('South').setValue('South'), + new StringSelectMenuOptionBuilder().setLabel('East').setValue('East'), + new StringSelectMenuOptionBuilder().setLabel('West').setValue('West'), + ), + ), + ) + .addActionRowComponents( + new ActionRowBuilder().addComponents( + new StringSelectMenuBuilder() + .setCustomId('version') + .setPlaceholder('Select Minecaft version') + .addOptions( + new StringSelectMenuOptionBuilder().setLabel('1.8.9').setValue('1.8.9'), + new StringSelectMenuOptionBuilder().setLabel('1.21').setValue('1.21'), + ), + ), + ) + .addActionRowComponents( + new ActionRowBuilder().addComponents( + new ButtonBuilder().setStyle(ButtonStyle.Secondary).setLabel('Remember my choices').setCustomId('save'), ), - ]; + ); await interaction .reply({ - components: components, + components: [farmInfoComponent, settingsComponent], allowedMentions: { repliedUser: false }, }) .catch(() => undefined); From 0f4f30456f994056cfc4aa765994e198d74921b6 Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Thu, 22 May 2025 14:03:59 -0700 Subject: [PATCH 13/61] formatting --- src/commands/farm/info.ts | 40 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index ab490e3..8455262 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -52,37 +52,31 @@ async function autocomplete(interaction: AutocompleteInteraction) { export default command; async function execute(interaction: ChatInputCommandInteraction, settings?: UserSettings) { - let design = farmsData.chisslMelon; - let depthStriderLevel = 1 as DepthStriderLevels; - let orienation = "North" as Direction; - let version = "1.8.9" as MinecraftVersion; + const design = farmsData.chisslMelon; + const depthStriderLevel = 1 as DepthStriderLevels; + const orienation = 'North' as Direction; + const version = '1.8.9' as MinecraftVersion; - let farmInfoComponent = new ContainerBuilder() + const farmInfoComponent = new ContainerBuilder() + .addTextDisplayComponents(new TextDisplayBuilder().setContent(`# ${design.name}`)) .addTextDisplayComponents( - new TextDisplayBuilder().setContent(`# ${design.name}`), - ) - .addTextDisplayComponents( - new TextDisplayBuilder().setContent(`Yaw: ${design.angle.yaw}, Pitch: ${design.angle.pitch}\nSpeed: ${design.speed.speed}, Depth strider level: ${depthStriderLevel}`), - ) - .addSeparatorComponents( - new SeparatorBuilder().setSpacing(SeparatorSpacingSize.Small).setDivider(true), - ) - .addTextDisplayComponents( - new TextDisplayBuilder().setContent(`bps: ${design.bps}\nLane time: \nKeys used: `), - ) - .addSeparatorComponents( - new SeparatorBuilder().setSpacing(SeparatorSpacingSize.Small).setDivider(true), + new TextDisplayBuilder().setContent( + `Yaw: ${design.angle.yaw}, Pitch: ${design.angle.pitch}\nSpeed: ${design.speed.speed}, Depth strider level: ${depthStriderLevel}`, + ), ) + .addSeparatorComponents(new SeparatorBuilder().setSpacing(SeparatorSpacingSize.Small).setDivider(true)) + .addTextDisplayComponents(new TextDisplayBuilder().setContent(`bps: ${design.bps}\nLane time: \nKeys used: `)) + .addSeparatorComponents(new SeparatorBuilder().setSpacing(SeparatorSpacingSize.Small).setDivider(true)) .addTextDisplayComponents( // todo: dont have field/value if there isnt an example - new TextDisplayBuilder().setContent(`Tutorial video: ${design.tutorials?.video ?? 'n/a'}\nDiscussion thread: ${design.tutorials?.thread ?? 'n/a'}\nVisitable example: ${design.tutorials?.garden ?? 'n/a'}`), - ) - .addSeparatorComponents( - new SeparatorBuilder().setSpacing(SeparatorSpacingSize.Small).setDivider(true), + new TextDisplayBuilder().setContent( + `Tutorial video: ${design.tutorials?.video ?? 'n/a'}\nDiscussion thread: ${design.tutorials?.thread ?? 'n/a'}\nVisitable example: ${design.tutorials?.garden ?? 'n/a'}`, + ), ) + .addSeparatorComponents(new SeparatorBuilder().setSpacing(SeparatorSpacingSize.Small).setDivider(true)) .addTextDisplayComponents( // todo: dont have field if there isnt any authors - new TextDisplayBuilder().setContent(`-# Authors: ${design.authors?.join(", ") ?? 'n/a'}`), + new TextDisplayBuilder().setContent(`-# Authors: ${design.authors?.join(', ') ?? 'n/a'}`), ); const settingsComponent = new ContainerBuilder() From d0d9052afb5686c37864bc2689fc93fde209ea06 Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Thu, 22 May 2025 14:28:23 -0700 Subject: [PATCH 14/61] add movement calculator and lane time --- src/commands/farm/info.ts | 44 ++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index 8455262..e9c18b7 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -14,7 +14,7 @@ import { StringSelectMenuOptionBuilder, TextDisplayBuilder, } from 'discord.js'; -import { DepthStriderLevels, Direction, MinecraftVersion, farmDesigns, farmsData } from 'farming-weight'; +import { DepthStriderLevels, Direction, MinecraftVersion, farmDesigns, farmInfo, farmsData } from 'farming-weight'; import { $ZodAny } from 'zod/v4/core'; const command = new EliteCommand({ @@ -57,15 +57,26 @@ async function execute(interaction: ChatInputCommandInteraction, settings?: User const orienation = 'North' as Direction; const version = '1.8.9' as MinecraftVersion; + const speed = await calcSpeed( + design.speed, + version, + depthStriderLevel, + ); + + const blocksPerSecond = await calcBlocksPerSecond( + speed, + design.angle.yaw, + ); + const farmInfoComponent = new ContainerBuilder() .addTextDisplayComponents(new TextDisplayBuilder().setContent(`# ${design.name}`)) .addTextDisplayComponents( new TextDisplayBuilder().setContent( - `Yaw: ${design.angle.yaw}, Pitch: ${design.angle.pitch}\nSpeed: ${design.speed.speed}, Depth strider level: ${depthStriderLevel}`, + `Yaw: ${design.angle.yaw}, Pitch: ${design.angle.pitch}\nSpeed: ${speed}, Depth strider level: ${depthStriderLevel}`, ), ) .addSeparatorComponents(new SeparatorBuilder().setSpacing(SeparatorSpacingSize.Small).setDivider(true)) - .addTextDisplayComponents(new TextDisplayBuilder().setContent(`bps: ${design.bps}\nLane time: \nKeys used: `)) + .addTextDisplayComponents(new TextDisplayBuilder().setContent(`bps: ${design.bps}\nLane time: ${480 / blocksPerSecond}\nKeys used: `)) .addSeparatorComponents(new SeparatorBuilder().setSpacing(SeparatorSpacingSize.Small).setDivider(true)) .addTextDisplayComponents( // todo: dont have field/value if there isnt an example @@ -132,11 +143,8 @@ async function execute(interaction: ChatInputCommandInteraction, settings?: User } async function calcSpeed( - currentSpeed: number, - usesSoulSand?: boolean, - designVersion?: MinecraftVersion, + designSpeed: farmInfo["speed"], targetVersion?: MinecraftVersion, - currentDepthStrider?: DepthStriderLevels, targetDepthStrider?: DepthStriderLevels, ): Promise { const versionMultiplier = { @@ -144,15 +152,27 @@ async function calcSpeed( '1.21': 0.5, }; - let speed = currentSpeed; + let speed = designSpeed.speed; - if (currentDepthStrider && targetDepthStrider) { - speed *= targetDepthStrider / currentDepthStrider; + if (designSpeed.depthStrider && targetDepthStrider) { + speed *= targetDepthStrider / designSpeed.depthStrider; } - if (usesSoulSand && designVersion && targetVersion) { - speed *= versionMultiplier[targetVersion] / versionMultiplier[designVersion]; + if (designSpeed.soulSand && designSpeed.buildVersion && targetVersion) { + speed *= versionMultiplier[targetVersion] / versionMultiplier[designSpeed.buildVersion]; } return speed; } + +async function calcBlocksPerSecond(speed: number, yaw: number): Promise { + if (speed <= 0) return Infinity; + + yaw = ((yaw % 360) + 360) % 360; + + const angleOffset = yaw % 90; + const effectiveSpeed = angleOffset === 0 ? speed : speed * Math.cos((angleOffset * Math.PI) / 180); + + // https://minecraft.fandom.com/wiki/Walking + return effectiveSpeed * 4.317 / 100; +} From 1e71fce83983773c2dbb2bb3d8ccdae0e8717b2b Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Thu, 22 May 2025 15:38:20 -0700 Subject: [PATCH 15/61] account for holding w --- src/commands/farm/info.ts | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index e9c18b7..74aff43 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -14,7 +14,15 @@ import { StringSelectMenuOptionBuilder, TextDisplayBuilder, } from 'discord.js'; -import { DepthStriderLevels, Direction, MinecraftVersion, farmDesigns, farmInfo, farmsData } from 'farming-weight'; +import { + DepthStriderLevels, + Direction, + FarmingMethod, + MinecraftVersion, + farmDesigns, + farmInfo, + farmsData, +} from 'farming-weight'; import { $ZodAny } from 'zod/v4/core'; const command = new EliteCommand({ @@ -57,16 +65,9 @@ async function execute(interaction: ChatInputCommandInteraction, settings?: User const orienation = 'North' as Direction; const version = '1.8.9' as MinecraftVersion; - const speed = await calcSpeed( - design.speed, - version, - depthStriderLevel, - ); + const speed = await calcSpeed(design.speed, version, depthStriderLevel); - const blocksPerSecond = await calcBlocksPerSecond( - speed, - design.angle.yaw, - ); + const blocksPerSecond = await calcBlocksPerSecond(speed, design.angle.yaw, design.speed.method); const farmInfoComponent = new ContainerBuilder() .addTextDisplayComponents(new TextDisplayBuilder().setContent(`# ${design.name}`)) @@ -76,7 +77,9 @@ async function execute(interaction: ChatInputCommandInteraction, settings?: User ), ) .addSeparatorComponents(new SeparatorBuilder().setSpacing(SeparatorSpacingSize.Small).setDivider(true)) - .addTextDisplayComponents(new TextDisplayBuilder().setContent(`bps: ${design.bps}\nLane time: ${480 / blocksPerSecond}\nKeys used: `)) + .addTextDisplayComponents( + new TextDisplayBuilder().setContent(`bps: ${design.bps}\nLane time: ${480 / blocksPerSecond}\nKeys used: `), + ) .addSeparatorComponents(new SeparatorBuilder().setSpacing(SeparatorSpacingSize.Small).setDivider(true)) .addTextDisplayComponents( // todo: dont have field/value if there isnt an example @@ -143,7 +146,7 @@ async function execute(interaction: ChatInputCommandInteraction, settings?: User } async function calcSpeed( - designSpeed: farmInfo["speed"], + designSpeed: farmInfo['speed'], targetVersion?: MinecraftVersion, targetDepthStrider?: DepthStriderLevels, ): Promise { @@ -165,14 +168,16 @@ async function calcSpeed( return speed; } -async function calcBlocksPerSecond(speed: number, yaw: number): Promise { - if (speed <= 0) return Infinity; +async function calcBlocksPerSecond(speed: number, yaw: number, method: FarmingMethod): Promise { + if (method === 'running into wall' && yaw === 0) { + speed *= 1.02042464775; + yaw = 45; + } - yaw = ((yaw % 360) + 360) % 360; + const angleOffset = Math.abs(yaw) % 90; - const angleOffset = yaw % 90; const effectiveSpeed = angleOffset === 0 ? speed : speed * Math.cos((angleOffset * Math.PI) / 180); // https://minecraft.fandom.com/wiki/Walking - return effectiveSpeed * 4.317 / 100; + return (effectiveSpeed * 4.3171) / 100; } From 477343ce18a3aad020efae3f4c886a936cc2063f Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Tue, 27 May 2025 10:49:27 -0700 Subject: [PATCH 16/61] fix search command description --- src/commands/farm/search.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/farm/search.ts b/src/commands/farm/search.ts index 0e82f9b..30a32b3 100644 --- a/src/commands/farm/search.ts +++ b/src/commands/farm/search.ts @@ -5,7 +5,7 @@ import { AutocompleteInteraction, ChatInputCommandInteraction } from 'discord.js const command = new EliteCommand({ name: 'search', - description: 'Get info about a farm design!', + description: 'Search for a farm design!', access: CommandAccess.Everywhere, type: CommandType.Slash, subCommand: true, From 4fff6ba6d020b0661bc8f3e58345c05832378a62 Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Wed, 4 Jun 2025 09:41:04 -0700 Subject: [PATCH 17/61] stuff stuff? travis scott reference??? --- src/commands/farm/info.ts | 42 +++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index 74aff43..66fae26 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -19,11 +19,11 @@ import { Direction, FarmingMethod, MinecraftVersion, + ResourceType, farmDesigns, farmInfo, farmsData, } from 'farming-weight'; -import { $ZodAny } from 'zod/v4/core'; const command = new EliteCommand({ name: 'info', @@ -60,11 +60,17 @@ async function autocomplete(interaction: AutocompleteInteraction) { export default command; async function execute(interaction: ChatInputCommandInteraction, settings?: UserSettings) { - const design = farmsData.chisslMelon; - const depthStriderLevel = 1 as DepthStriderLevels; + const design = farmsData[interaction.options.getString('design', false) ?? -1]; + if (!design) return; + + const depthStriderLevel = design.speed.depthStrider; const orienation = 'North' as Direction; const version = '1.8.9' as MinecraftVersion; + const resources = design.resources + ?.filter((r) => r.type !== ResourceType.Schematic) + .map((r) => `${r.type}: ${r.source}`).join("\n"); + const speed = await calcSpeed(design.speed, version, depthStriderLevel); const blocksPerSecond = await calcBlocksPerSecond(speed, design.angle.yaw, design.speed.method); @@ -80,18 +86,23 @@ async function execute(interaction: ChatInputCommandInteraction, settings?: User .addTextDisplayComponents( new TextDisplayBuilder().setContent(`bps: ${design.bps}\nLane time: ${480 / blocksPerSecond}\nKeys used: `), ) - .addSeparatorComponents(new SeparatorBuilder().setSpacing(SeparatorSpacingSize.Small).setDivider(true)) - .addTextDisplayComponents( - // todo: dont have field/value if there isnt an example - new TextDisplayBuilder().setContent( - `Tutorial video: ${design.tutorials?.video ?? 'n/a'}\nDiscussion thread: ${design.tutorials?.thread ?? 'n/a'}\nVisitable example: ${design.tutorials?.garden ?? 'n/a'}`, - ), - ) - .addSeparatorComponents(new SeparatorBuilder().setSpacing(SeparatorSpacingSize.Small).setDivider(true)) - .addTextDisplayComponents( - // todo: dont have field if there isnt any authors - new TextDisplayBuilder().setContent(`-# Authors: ${design.authors?.join(', ') ?? 'n/a'}`), - ); + + + if (resources) { + farmInfoComponent + .addSeparatorComponents(new SeparatorBuilder().setSpacing(SeparatorSpacingSize.Small).setDivider(true)) + .addTextDisplayComponents( + new TextDisplayBuilder().setContent(resources), + ); + } + + if (design.authors) { + farmInfoComponent + .addSeparatorComponents(new SeparatorBuilder().setSpacing(SeparatorSpacingSize.Small).setDivider(true)) + .addTextDisplayComponents( + new TextDisplayBuilder().setContent(`-# Authors: ${design.authors.join(', ')}`), + ); + } const settingsComponent = new ContainerBuilder() .addTextDisplayComponents(new TextDisplayBuilder().setContent('# Settings')) @@ -150,6 +161,7 @@ async function calcSpeed( targetVersion?: MinecraftVersion, targetDepthStrider?: DepthStriderLevels, ): Promise { + // todo: fix const versionMultiplier = { '1.8.9': 0.4, '1.21': 0.5, From 7b90ea4bc697350e83fdfc79beddf6fce1cb9d0e Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Wed, 4 Jun 2025 10:09:09 -0700 Subject: [PATCH 18/61] uncle bob martin has a gun to my head --- src/commands/farm/info.ts | 43 ++++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index 66fae26..a1ffdbd 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -59,49 +59,47 @@ async function autocomplete(interaction: AutocompleteInteraction) { export default command; -async function execute(interaction: ChatInputCommandInteraction, settings?: UserSettings) { +async function execute(interaction: ChatInputCommandInteraction) { const design = farmsData[interaction.options.getString('design', false) ?? -1]; if (!design) return; const depthStriderLevel = design.speed.depthStrider; - const orienation = 'North' as Direction; + const direction = 'North' as Direction; const version = '1.8.9' as MinecraftVersion; const resources = design.resources ?.filter((r) => r.type !== ResourceType.Schematic) - .map((r) => `${r.type}: ${r.source}`).join("\n"); + .map((r) => `${r.type}: ${r.source}`) + .join('\n'); const speed = await calcSpeed(design.speed, version, depthStriderLevel); const blocksPerSecond = await calcBlocksPerSecond(speed, design.angle.yaw, design.speed.method); + const yaw = await fixDesignAngle(design.angle.yaw, direction); + const farmInfoComponent = new ContainerBuilder() .addTextDisplayComponents(new TextDisplayBuilder().setContent(`# ${design.name}`)) .addTextDisplayComponents( new TextDisplayBuilder().setContent( - `Yaw: ${design.angle.yaw}, Pitch: ${design.angle.pitch}\nSpeed: ${speed}, Depth strider level: ${depthStriderLevel}`, + `Yaw: ${yaw}, Pitch: ${design.angle.pitch}\nSpeed: ${speed}, Depth strider level: ${depthStriderLevel}`, ), ) .addSeparatorComponents(new SeparatorBuilder().setSpacing(SeparatorSpacingSize.Small).setDivider(true)) .addTextDisplayComponents( new TextDisplayBuilder().setContent(`bps: ${design.bps}\nLane time: ${480 / blocksPerSecond}\nKeys used: `), - ) + ); - if (resources) { farmInfoComponent .addSeparatorComponents(new SeparatorBuilder().setSpacing(SeparatorSpacingSize.Small).setDivider(true)) - .addTextDisplayComponents( - new TextDisplayBuilder().setContent(resources), - ); + .addTextDisplayComponents(new TextDisplayBuilder().setContent(resources)); } if (design.authors) { farmInfoComponent .addSeparatorComponents(new SeparatorBuilder().setSpacing(SeparatorSpacingSize.Small).setDivider(true)) - .addTextDisplayComponents( - new TextDisplayBuilder().setContent(`-# Authors: ${design.authors.join(', ')}`), - ); + .addTextDisplayComponents(new TextDisplayBuilder().setContent(`-# Authors: ${design.authors.join(', ')}`)); } const settingsComponent = new ContainerBuilder() @@ -193,3 +191,24 @@ async function calcBlocksPerSecond(speed: number, yaw: number, method: FarmingMe // https://minecraft.fandom.com/wiki/Walking return (effectiveSpeed * 4.3171) / 100; } + +async function fixDesignAngle(designYaw: number, direction: Direction): Promise { + const yaw = designYaw + directionYawOffset('South', direction); + + return normalizeAngle(yaw); +} + +function directionYawOffset(from: Direction, to: Direction): number { + const yawMap: Record = { + North: 180, + East: -90, + South: 0, + West: 90, + }; + + return normalizeAngle(yawMap[to] - yawMap[from]); +} + +function normalizeAngle(angle: number) { + return ((angle + 180) % 360) - 180; +} From 6782ef5abb1f216c31217ca8a82ed6d5ae485ecc Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Wed, 4 Jun 2025 10:29:44 -0700 Subject: [PATCH 19/61] use EliteContainer --- src/commands/farm/info.ts | 40 +++++++++++++-------------------------- 1 file changed, 13 insertions(+), 27 deletions(-) diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index a1ffdbd..e64f606 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -1,18 +1,15 @@ import { UserSettings } from 'api/elite.js'; import { CommandAccess, CommandType, EliteCommand, SlashCommandOptionType } from 'classes/commands/index.js'; +import { EliteContainer } from 'classes/components.js'; import { ActionRowBuilder, AutocompleteInteraction, ButtonBuilder, ButtonStyle, ChatInputCommandInteraction, - ContainerBuilder, MessageActionRowComponentBuilder, - SeparatorBuilder, - SeparatorSpacingSize, StringSelectMenuBuilder, StringSelectMenuOptionBuilder, - TextDisplayBuilder, } from 'discord.js'; import { DepthStriderLevels, @@ -59,7 +56,7 @@ async function autocomplete(interaction: AutocompleteInteraction) { export default command; -async function execute(interaction: ChatInputCommandInteraction) { +async function execute(interaction: ChatInputCommandInteraction, settings?: UserSettings) { const design = farmsData[interaction.options.getString('design', false) ?? -1]; if (!design) return; @@ -78,32 +75,26 @@ async function execute(interaction: ChatInputCommandInteraction) { const yaw = await fixDesignAngle(design.angle.yaw, direction); - const farmInfoComponent = new ContainerBuilder() - .addTextDisplayComponents(new TextDisplayBuilder().setContent(`# ${design.name}`)) - .addTextDisplayComponents( - new TextDisplayBuilder().setContent( - `Yaw: ${yaw}, Pitch: ${design.angle.pitch}\nSpeed: ${speed}, Depth strider level: ${depthStriderLevel}`, - ), - ) - .addSeparatorComponents(new SeparatorBuilder().setSpacing(SeparatorSpacingSize.Small).setDivider(true)) - .addTextDisplayComponents( - new TextDisplayBuilder().setContent(`bps: ${design.bps}\nLane time: ${480 / blocksPerSecond}\nKeys used: `), - ); + const farmInfoComponent = new EliteContainer(settings) + .addTitle(`# ${design.name}`) + .addDescription(`Yaw: ${yaw}, Pitch: ${design.angle.pitch}\nSpeed: ${speed}, Depth strider level: ${depthStriderLevel}`) + .addSeperator() + .addDescription(`bps: ${design.bps}\nLane time: ${480 / blocksPerSecond}\nKeys used: `); if (resources) { farmInfoComponent - .addSeparatorComponents(new SeparatorBuilder().setSpacing(SeparatorSpacingSize.Small).setDivider(true)) - .addTextDisplayComponents(new TextDisplayBuilder().setContent(resources)); + .addSeperator() + .addDescription(resources); } if (design.authors) { farmInfoComponent - .addSeparatorComponents(new SeparatorBuilder().setSpacing(SeparatorSpacingSize.Small).setDivider(true)) - .addTextDisplayComponents(new TextDisplayBuilder().setContent(`-# Authors: ${design.authors.join(', ')}`)); + .addSeperator() + .addDescription(`-# Authors: ${design.authors.join(', ')}`); } - const settingsComponent = new ContainerBuilder() - .addTextDisplayComponents(new TextDisplayBuilder().setContent('# Settings')) + const settingsComponent = new EliteContainer(settings) + .addTitle('# Settings') .addActionRowComponents( new ActionRowBuilder().addComponents( new StringSelectMenuBuilder() @@ -139,11 +130,6 @@ async function execute(interaction: ChatInputCommandInteraction) { new StringSelectMenuOptionBuilder().setLabel('1.21').setValue('1.21'), ), ), - ) - .addActionRowComponents( - new ActionRowBuilder().addComponents( - new ButtonBuilder().setStyle(ButtonStyle.Secondary).setLabel('Remember my choices').setCustomId('save'), - ), ); await interaction From 8ff293e881cbf238f8a42d92c629f4306c6dd926 Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Wed, 4 Jun 2025 10:31:16 -0700 Subject: [PATCH 20/61] add footer --- src/commands/farm/info.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index e64f606..5d53151 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -93,6 +93,8 @@ async function execute(interaction: ChatInputCommandInteraction, settings?: User .addDescription(`-# Authors: ${design.authors.join(', ')}`); } + farmInfoComponent.addFooter(); + const settingsComponent = new EliteContainer(settings) .addTitle('# Settings') .addActionRowComponents( @@ -130,7 +132,8 @@ async function execute(interaction: ChatInputCommandInteraction, settings?: User new StringSelectMenuOptionBuilder().setLabel('1.21').setValue('1.21'), ), ), - ); + ) + .addFooter(); await interaction .reply({ From d7cd22f5e223958227c600abe7fbbb2d32066e6b Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Wed, 4 Jun 2025 10:42:47 -0700 Subject: [PATCH 21/61] format --- src/commands/farm/info.ts | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index 5d53151..069ea15 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -4,8 +4,6 @@ import { EliteContainer } from 'classes/components.js'; import { ActionRowBuilder, AutocompleteInteraction, - ButtonBuilder, - ButtonStyle, ChatInputCommandInteraction, MessageActionRowComponentBuilder, StringSelectMenuBuilder, @@ -77,20 +75,18 @@ async function execute(interaction: ChatInputCommandInteraction, settings?: User const farmInfoComponent = new EliteContainer(settings) .addTitle(`# ${design.name}`) - .addDescription(`Yaw: ${yaw}, Pitch: ${design.angle.pitch}\nSpeed: ${speed}, Depth strider level: ${depthStriderLevel}`) + .addDescription( + `Yaw: ${yaw}, Pitch: ${design.angle.pitch}\nSpeed: ${speed}, Depth strider level: ${depthStriderLevel}`, + ) .addSeperator() .addDescription(`bps: ${design.bps}\nLane time: ${480 / blocksPerSecond}\nKeys used: `); if (resources) { - farmInfoComponent - .addSeperator() - .addDescription(resources); + farmInfoComponent.addSeperator().addDescription(resources); } if (design.authors) { - farmInfoComponent - .addSeperator() - .addDescription(`-# Authors: ${design.authors.join(', ')}`); + farmInfoComponent.addSeperator().addDescription(`-# Authors: ${design.authors.join(', ')}`); } farmInfoComponent.addFooter(); From 053fba950eef79f838225f2db2eb61a39c307def Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Wed, 4 Jun 2025 10:45:51 -0700 Subject: [PATCH 22/61] remove params --- COMMANDS.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/COMMANDS.md b/COMMANDS.md index 4469dab..e750ab1 100644 --- a/COMMANDS.md +++ b/COMMANDS.md @@ -126,9 +126,6 @@ Get info on a specific farm design including, angles, speeds, tutorials and more **Usage:** `/farm info` \ `[design]: ` -`(direction): ` -`(depth strider): ` -`(version): ` farm info From 4b6f36cf2258667ec894cb46e5aaa63d917a8df1 Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Wed, 4 Jun 2025 11:48:09 -0700 Subject: [PATCH 23/61] farm search command todo: button for each one that edits message to farm info component? --- src/commands/farm/search.ts | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/commands/farm/search.ts b/src/commands/farm/search.ts index 30a32b3..64d4772 100644 --- a/src/commands/farm/search.ts +++ b/src/commands/farm/search.ts @@ -1,7 +1,9 @@ import { UserSettings } from 'api/elite.js'; import { eliteCropOption } from 'autocomplete/crops.js'; import { CommandAccess, CommandType, EliteCommand, SlashCommandOptionType } from 'classes/commands/index.js'; -import { AutocompleteInteraction, ChatInputCommandInteraction } from 'discord.js'; +import { EliteContainer } from 'classes/components.js'; +import { ChatInputCommandInteraction } from 'discord.js'; +import { farmsData, getCropFromName } from 'farming-weight'; const command = new EliteCommand({ name: 'search', @@ -17,4 +19,32 @@ const command = new EliteCommand({ export default command; -async function execute(interaction: ChatInputCommandInteraction, settings?: UserSettings) {} +async function execute(interaction: ChatInputCommandInteraction, settings?: UserSettings) { + const cropName = interaction.options.getString('crop', false); + if (!cropName) return; + const crop = getCropFromName(cropName); + if (!crop) return; + + const farms = Object.fromEntries( + Object.entries(farmsData) + .filter(([, farm]) => farm.crops.includes(crop)) + .sort(([, a], [, b]) => b.bps - a.bps), + ); + + const component = new EliteContainer(settings).addTitle(`Farm designs for ${cropName}`); + + Object.entries(farms).forEach(([, data], i) => { + if (i !== 1) { + component.addSeperator(); + } + + component.addDescription(`### ${data.name}`).addDescription(`bps: ${data.bps}`); + }); + + await interaction + .reply({ + components: [component], + allowedMentions: { repliedUser: false }, + }) + .catch(() => undefined); +} From 3e33ba62516bc21e85b6370b9e69c66221069e09 Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Wed, 4 Jun 2025 11:51:45 -0700 Subject: [PATCH 24/61] fix title --- src/commands/farm/search.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/farm/search.ts b/src/commands/farm/search.ts index 64d4772..09681ba 100644 --- a/src/commands/farm/search.ts +++ b/src/commands/farm/search.ts @@ -31,7 +31,7 @@ async function execute(interaction: ChatInputCommandInteraction, settings?: User .sort(([, a], [, b]) => b.bps - a.bps), ); - const component = new EliteContainer(settings).addTitle(`Farm designs for ${cropName}`); + const component = new EliteContainer(settings).addTitle(`# Farm designs for ${cropName}`); Object.entries(farms).forEach(([, data], i) => { if (i !== 1) { From 5617f9d4a4725b8e5f8a44f6428d369a4fe84d5a Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Wed, 4 Jun 2025 14:31:24 -0700 Subject: [PATCH 25/61] idk --- src/commands/farm/info.ts | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index 069ea15..fe5b709 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -54,29 +54,39 @@ async function autocomplete(interaction: AutocompleteInteraction) { export default command; +interface FarmSettings { + depthStrider: DepthStriderLevels, + direction: Direction, + version: MinecraftVersion, +} + +const farmSettings: FarmSettings = { + depthStrider: 3, + direction: 'East', + version: '1.8.9', +} + async function execute(interaction: ChatInputCommandInteraction, settings?: UserSettings) { const design = farmsData[interaction.options.getString('design', false) ?? -1]; if (!design) return; - const depthStriderLevel = design.speed.depthStrider; - const direction = 'North' as Direction; - const version = '1.8.9' as MinecraftVersion; + farmSettings.depthStrider = design.speed.depthStrider ?? 3; const resources = design.resources ?.filter((r) => r.type !== ResourceType.Schematic) .map((r) => `${r.type}: ${r.source}`) .join('\n'); - const speed = await calcSpeed(design.speed, version, depthStriderLevel); + const speed = await calcSpeed(design.speed, farmSettings.version, farmSettings.depthStrider); const blocksPerSecond = await calcBlocksPerSecond(speed, design.angle.yaw, design.speed.method); - const yaw = await fixDesignAngle(design.angle.yaw, direction); + const yaw = await fixDesignAngle(design.angle.yaw, farmSettings.direction); const farmInfoComponent = new EliteContainer(settings) .addTitle(`# ${design.name}`) .addDescription( - `Yaw: ${yaw}, Pitch: ${design.angle.pitch}\nSpeed: ${speed}, Depth strider level: ${depthStriderLevel}`, + `Yaw: ${yaw}, Pitch: ${design.angle.pitch}\nSpeed: ${speed}, Depth Strider level: ${farmSettings.depthStrider}`, ) .addSeperator() .addDescription(`bps: ${design.bps}\nLane time: ${480 / blocksPerSecond}\nKeys used: `); @@ -96,7 +106,7 @@ async function execute(interaction: ChatInputCommandInteraction, settings?: User .addActionRowComponents( new ActionRowBuilder().addComponents( new StringSelectMenuBuilder() - .setCustomId('depth_strider') + .setCustomId('depthStrider') .setPlaceholder('Select the depth strider level you use') .addOptions( new StringSelectMenuOptionBuilder().setLabel('Depth Strider 1').setValue('1'), @@ -124,7 +134,7 @@ async function execute(interaction: ChatInputCommandInteraction, settings?: User .setCustomId('version') .setPlaceholder('Select Minecaft version') .addOptions( - new StringSelectMenuOptionBuilder().setLabel('1.8.9').setValue('1.8.9'), + new StringSelectMenuOptionBuilder().setLabel('1.8.9').setValue('1.8.9').setDefault(true), new StringSelectMenuOptionBuilder().setLabel('1.21').setValue('1.21'), ), ), From a14d35fc60f5560bdae89d535eec29b83c4f94b7 Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Wed, 4 Jun 2025 14:45:02 -0700 Subject: [PATCH 26/61] format --- src/commands/farm/info.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index fe5b709..559eb74 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -55,16 +55,16 @@ async function autocomplete(interaction: AutocompleteInteraction) { export default command; interface FarmSettings { - depthStrider: DepthStriderLevels, - direction: Direction, - version: MinecraftVersion, + depthStrider: DepthStriderLevels; + direction: Direction; + version: MinecraftVersion; } const farmSettings: FarmSettings = { depthStrider: 3, direction: 'East', version: '1.8.9', -} +}; async function execute(interaction: ChatInputCommandInteraction, settings?: UserSettings) { const design = farmsData[interaction.options.getString('design', false) ?? -1]; From f8009a344cf1d44165c44ab5557454a9824908d6 Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Thu, 5 Jun 2025 09:17:26 -0700 Subject: [PATCH 27/61] refactor --- src/commands/farm/search.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/commands/farm/search.ts b/src/commands/farm/search.ts index 09681ba..8904a8f 100644 --- a/src/commands/farm/search.ts +++ b/src/commands/farm/search.ts @@ -33,12 +33,8 @@ async function execute(interaction: ChatInputCommandInteraction, settings?: User const component = new EliteContainer(settings).addTitle(`# Farm designs for ${cropName}`); - Object.entries(farms).forEach(([, data], i) => { - if (i !== 1) { - component.addSeperator(); - } - - component.addDescription(`### ${data.name}`).addDescription(`bps: ${data.bps}`); + Object.values(farms).forEach((data, i, arr) => { + component.addDescription(`### ${data.name}`).addDescription(`bps: ${data.bps}`, i < arr.length - 1); }); await interaction From 43964f84d1f38deb861e919ef60ed543687dd8d9 Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Thu, 5 Jun 2025 09:58:16 -0700 Subject: [PATCH 28/61] add button for search command top open info command this very likely doesnt work --- src/classes/components.ts | 22 +++++++++++++++++--- src/commands/farm/info.ts | 26 +++++++++++++++++++---- src/commands/farm/search.ts | 41 +++++++++++++++++++++++++++++-------- 3 files changed, 73 insertions(+), 16 deletions(-) diff --git a/src/classes/components.ts b/src/classes/components.ts index 7b5bb89..2ec53b4 100644 --- a/src/classes/components.ts +++ b/src/classes/components.ts @@ -47,10 +47,19 @@ export class EliteContainer extends ContainerBuilder { return this; } - addDescription(description: string, seperator = false) { - this.addText(description); + addDescription(description: string, separator = false, button?: [string, string, ButtonStyle]) { + if (button) { + this.addSectionComponents( + new EliteSectionBuilder() + .setButtonAccessory(new ButtonBuilder().setStyle(button[2]).setLabel(button[0]).setCustomId(button[1])) + .addText(description), + ); + } else { + this.addText(description); + } + + if (separator) this.addSeperator(); - if (seperator) this.addSeperator(); return this; } @@ -256,6 +265,13 @@ export class EliteContainer extends ContainerBuilder { } } +export class EliteSectionBuilder extends SectionBuilder { + addText(text: string) { + this.addTextDisplayComponents((t) => t.setContent(text)); + return this; + } +} + interface CollapsibleSection { id: number; radio?: boolean; diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index 559eb74..7e28cf6 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -4,7 +4,10 @@ import { EliteContainer } from 'classes/components.js'; import { ActionRowBuilder, AutocompleteInteraction, + ButtonBuilder, + ButtonStyle, ChatInputCommandInteraction, + ComponentBuilder, MessageActionRowComponentBuilder, StringSelectMenuBuilder, StringSelectMenuOptionBuilder, @@ -66,11 +69,16 @@ const farmSettings: FarmSettings = { version: '1.8.9', }; -async function execute(interaction: ChatInputCommandInteraction, settings?: UserSettings) { - const design = farmsData[interaction.options.getString('design', false) ?? -1]; +export async function execute( + interaction: ChatInputCommandInteraction, + settings?: UserSettings, + designOverride?: string, +) { + const designId = designOverride ?? interaction.options.getString('design', false) ?? ''; + const design = farmsData[designId]; if (!design) return; - farmSettings.depthStrider = design.speed.depthStrider ?? 3; + const components: (EliteContainer | ActionRowBuilder)[] = []; const resources = design.resources ?.filter((r) => r.type !== ResourceType.Schematic) @@ -101,6 +109,8 @@ async function execute(interaction: ChatInputCommandInteraction, settings?: User farmInfoComponent.addFooter(); + components.push(farmInfoComponent); + const settingsComponent = new EliteContainer(settings) .addTitle('# Settings') .addActionRowComponents( @@ -141,9 +151,17 @@ async function execute(interaction: ChatInputCommandInteraction, settings?: User ) .addFooter(); + components.push(settingsComponent); + + const settingsButton = new ActionRowBuilder().addComponents( + new ButtonBuilder().setStyle(ButtonStyle.Secondary).setLabel('Open Settings').setCustomId('settings'), + ); + + components.push(settingsButton); + await interaction .reply({ - components: [farmInfoComponent, settingsComponent], + components, allowedMentions: { repliedUser: false }, }) .catch(() => undefined); diff --git a/src/commands/farm/search.ts b/src/commands/farm/search.ts index 8904a8f..17e0925 100644 --- a/src/commands/farm/search.ts +++ b/src/commands/farm/search.ts @@ -2,8 +2,10 @@ import { UserSettings } from 'api/elite.js'; import { eliteCropOption } from 'autocomplete/crops.js'; import { CommandAccess, CommandType, EliteCommand, SlashCommandOptionType } from 'classes/commands/index.js'; import { EliteContainer } from 'classes/components.js'; -import { ChatInputCommandInteraction } from 'discord.js'; +import { NotYoursReply } from 'classes/embeds.js'; +import { ButtonStyle, ChatInputCommandInteraction, MessageFlags } from 'discord.js'; import { farmsData, getCropFromName } from 'farming-weight'; +import { execute as farmInfoCommand } from './info.js'; const command = new EliteCommand({ name: 'search', @@ -20,6 +22,8 @@ const command = new EliteCommand({ export default command; async function execute(interaction: ChatInputCommandInteraction, settings?: UserSettings) { + await interaction.deferReply(); + const cropName = interaction.options.getString('crop', false); if (!cropName) return; const crop = getCropFromName(cropName); @@ -33,14 +37,33 @@ async function execute(interaction: ChatInputCommandInteraction, settings?: User const component = new EliteContainer(settings).addTitle(`# Farm designs for ${cropName}`); - Object.values(farms).forEach((data, i, arr) => { - component.addDescription(`### ${data.name}`).addDescription(`bps: ${data.bps}`, i < arr.length - 1); + Object.entries(farms).forEach(([id, data], i, arr) => { + component + .addDescription(`### ${data.name}`) + .addDescription(`bps: ${data.bps}`, i < arr.length - 1, [data.name, id, ButtonStyle.Secondary]); + }); + + const reply = await interaction.editReply({ + components: [component], + allowedMentions: { repliedUser: false }, + flags: [MessageFlags.IsComponentsV2], + }); + + const collector = reply.createMessageComponentCollector({ + time: 120_000, }); - await interaction - .reply({ - components: [component], - allowedMentions: { repliedUser: false }, - }) - .catch(() => undefined); + collector.on('collect', async (inter) => { + if (inter.user.id !== interaction.user.id) { + return NotYoursReply(inter); + } + + collector.resetTimer(); + + await farmInfoCommand(interaction, settings, inter.customId); + + await inter.deleteReply(); + + return; + }); } From 967b2c0d102bb85641d597794ae75e331f7b86ac Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Thu, 5 Jun 2025 10:56:10 -0700 Subject: [PATCH 29/61] not that important anyway --- src/classes/components.ts | 35 +++++++++-------------------------- src/commands/farm/info.ts | 6 +++--- src/commands/farm/search.ts | 14 +++++++++++--- src/commands/rates.ts | 14 +++++++------- 4 files changed, 30 insertions(+), 39 deletions(-) diff --git a/src/classes/components.ts b/src/classes/components.ts index 2ec53b4..5760da9 100644 --- a/src/classes/components.ts +++ b/src/classes/components.ts @@ -3,7 +3,6 @@ import { ActionRowBuilder, BaseSelectMenuBuilder, ButtonBuilder, - ButtonInteraction, ButtonStyle, ContainerBuilder, Interaction, @@ -32,7 +31,7 @@ export class EliteContainer extends ContainerBuilder { } } - addTitle(title: string, seperator = true, backButton = '') { + addTitle(title: string, separator = true, backButton = '') { if (backButton) { this.addSectionComponents((s) => s @@ -43,27 +42,18 @@ export class EliteContainer extends ContainerBuilder { this.addText(title); } - if (seperator) this.addSeperator(); + if (separator) this.addSeparator(); return this; } - addDescription(description: string, separator = false, button?: [string, string, ButtonStyle]) { - if (button) { - this.addSectionComponents( - new EliteSectionBuilder() - .setButtonAccessory(new ButtonBuilder().setStyle(button[2]).setLabel(button[0]).setCustomId(button[1])) - .addText(description), - ); - } else { - this.addText(description); - } - - if (separator) this.addSeperator(); + addDescription(description: string, separator = false) { + this.addText(description); + if (separator) this.addSeparator(); return this; } - addSeperator(big = false, display = true) { + addSeparator(big = false, display = true) { this.addSeparatorComponents((a) => a.setSpacing(big ? SeparatorSpacingSize.Large : SeparatorSpacingSize.Small).setDivider(display), ); @@ -75,9 +65,9 @@ export class EliteContainer extends ContainerBuilder { return this; } - addFooter(seperator = true, backButton = '') { - if (seperator) { - this.addSeperator(); + addFooter(separator = true, backButton = '') { + if (separator) { + this.addSeparator(); } let text = '-# <:icon:1376644165588488212> [elitebot.dev]()'; @@ -265,13 +255,6 @@ export class EliteContainer extends ContainerBuilder { } } -export class EliteSectionBuilder extends SectionBuilder { - addText(text: string) { - this.addTextDisplayComponents((t) => t.setContent(text)); - return this; - } -} - interface CollapsibleSection { id: number; radio?: boolean; diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index 7e28cf6..77d5c77 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -96,15 +96,15 @@ export async function execute( .addDescription( `Yaw: ${yaw}, Pitch: ${design.angle.pitch}\nSpeed: ${speed}, Depth Strider level: ${farmSettings.depthStrider}`, ) - .addSeperator() + .addSeparator() .addDescription(`bps: ${design.bps}\nLane time: ${480 / blocksPerSecond}\nKeys used: `); if (resources) { - farmInfoComponent.addSeperator().addDescription(resources); + farmInfoComponent.addSeparator().addDescription(resources); } if (design.authors) { - farmInfoComponent.addSeperator().addDescription(`-# Authors: ${design.authors.join(', ')}`); + farmInfoComponent.addSeparator().addDescription(`-# Authors: ${design.authors.join(', ')}`); } farmInfoComponent.addFooter(); diff --git a/src/commands/farm/search.ts b/src/commands/farm/search.ts index 17e0925..11dd18b 100644 --- a/src/commands/farm/search.ts +++ b/src/commands/farm/search.ts @@ -3,7 +3,7 @@ import { eliteCropOption } from 'autocomplete/crops.js'; import { CommandAccess, CommandType, EliteCommand, SlashCommandOptionType } from 'classes/commands/index.js'; import { EliteContainer } from 'classes/components.js'; import { NotYoursReply } from 'classes/embeds.js'; -import { ButtonStyle, ChatInputCommandInteraction, MessageFlags } from 'discord.js'; +import { ButtonBuilder, ButtonStyle, ChatInputCommandInteraction, MessageFlags, SectionBuilder } from 'discord.js'; import { farmsData, getCropFromName } from 'farming-weight'; import { execute as farmInfoCommand } from './info.js'; @@ -37,10 +37,18 @@ async function execute(interaction: ChatInputCommandInteraction, settings?: User const component = new EliteContainer(settings).addTitle(`# Farm designs for ${cropName}`); - Object.entries(farms).forEach(([id, data], i, arr) => { + Object.entries(farms).forEach(([id, data], i) => { + if (i !== 1) { + component.addSeparator(); + } + component .addDescription(`### ${data.name}`) - .addDescription(`bps: ${data.bps}`, i < arr.length - 1, [data.name, id, ButtonStyle.Secondary]); + .addSectionComponents( + new SectionBuilder() + .addTextDisplayComponents((t) => t.setContent(`bps: ${data.bps}`)) + .setButtonAccessory(new ButtonBuilder().setStyle(ButtonStyle.Secondary).setLabel(data.name).setCustomId(id)), + ); }); const reply = await interaction.editReply({ diff --git a/src/commands/rates.ts b/src/commands/rates.ts index fbef316..b90bfda 100644 --- a/src/commands/rates.ts +++ b/src/commands/rates.ts @@ -156,12 +156,12 @@ async function execute(interaction: ChatInputCommandInteraction, settings?: User const container = new EliteContainer(settings) .addTitle('## Farming Rates Calculator', false) .addDescription(description) - .addSeperator(); + .addSeparator(); const compactContainer = new EliteContainer(settings) .addTitle('## Farming Rates Calculator', false) .addDescription(description) - .addSeperator(); + .addSeparator(); const cropList = Object.keys(EliteCropEmojis) as Crop[]; @@ -192,11 +192,11 @@ async function execute(interaction: ChatInputCommandInteraction, settings?: User '\n\n**Custom Fortune Warning**\n-# The amount of fortune available varies depending on the crop. For the best results, only look at the crop your entered fortune is for.'; } - container.addSeperator(); + container.addSeparator(); container.addText("**What's my fortune?**\n-# " + details); container.addFooter(); - compactContainer.addSeperator(); + compactContainer.addSeparator(); compactContainer.addText("**What's my fortune?**\n-# " + details); compactContainer.addFooter(); @@ -256,7 +256,7 @@ async function execute(interaction: ChatInputCommandInteraction, settings?: User .addDescription( `Expected rates for **${fortuneInput?.toLocaleString() ?? `${cropInfo.details.fortune.toLocaleString()} (MAX)`}** Farming Fortune in **${timeName}**!${cropDetails}\n${bpsText}`, ) - .addSeperator() + .addSeparator() .addCollapsible({ header: '**NPC Profit**', collapsed: { @@ -272,7 +272,7 @@ async function execute(interaction: ChatInputCommandInteraction, settings?: User `\n### 3/4ths Fermento Armor\n:coin: ${threeFourthsTotal?.toLocaleString() ?? '0'} ⠀ ${(specialDifference).toLocaleString()} less coins (~${threeFourths.amount.toLocaleString()} ${threeFourths.type})`, }, }) - .addSeperator() + .addSeparator() .addCollapsible({ header: '**Bazaar Profit**', collapsed: { @@ -289,7 +289,7 @@ async function execute(interaction: ChatInputCommandInteraction, settings?: User `\n-# Prices used are averaged sell order prices, not insta-sell prices.`, }, }) - .addSeperator() + .addSeparator() .addCollapsible({ header: '**Collection Gain**', collapsed: { From b85124241a83321fb908dba378a9864cbfe6808e Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Thu, 5 Jun 2025 12:22:31 -0700 Subject: [PATCH 30/61] refactor --- src/commands/farm/search.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/commands/farm/search.ts b/src/commands/farm/search.ts index 11dd18b..059acf0 100644 --- a/src/commands/farm/search.ts +++ b/src/commands/farm/search.ts @@ -4,7 +4,7 @@ import { CommandAccess, CommandType, EliteCommand, SlashCommandOptionType } from import { EliteContainer } from 'classes/components.js'; import { NotYoursReply } from 'classes/embeds.js'; import { ButtonBuilder, ButtonStyle, ChatInputCommandInteraction, MessageFlags, SectionBuilder } from 'discord.js'; -import { farmsData, getCropFromName } from 'farming-weight'; +import { Crop, farmsData, getCropDisplayName, getCropFromName } from 'farming-weight'; import { execute as farmInfoCommand } from './info.js'; const command = new EliteCommand({ @@ -24,9 +24,7 @@ export default command; async function execute(interaction: ChatInputCommandInteraction, settings?: UserSettings) { await interaction.deferReply(); - const cropName = interaction.options.getString('crop', false); - if (!cropName) return; - const crop = getCropFromName(cropName); + const crop = interaction.options.getString('crop', false) as Crop; if (!crop) return; const farms = Object.fromEntries( @@ -35,7 +33,7 @@ async function execute(interaction: ChatInputCommandInteraction, settings?: User .sort(([, a], [, b]) => b.bps - a.bps), ); - const component = new EliteContainer(settings).addTitle(`# Farm designs for ${cropName}`); + const component = new EliteContainer(settings).addTitle(`# Farm designs for ${getCropDisplayName(crop)}`); Object.entries(farms).forEach(([id, data], i) => { if (i !== 1) { From 629b6ef2c1681db0ae55367426f992f38ca32cce Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Fri, 20 Jun 2025 20:45:51 -0700 Subject: [PATCH 31/61] shrug --- src/autocomplete/crops.ts | 5 ++++- src/commands/farm/command.ts | 2 +- src/commands/farm/info.ts | 6 ++++-- src/commands/farm/search.ts | 6 +++--- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/autocomplete/crops.ts b/src/autocomplete/crops.ts index b1c9120..b1acaff 100644 --- a/src/autocomplete/crops.ts +++ b/src/autocomplete/crops.ts @@ -15,7 +15,10 @@ export async function autocomplete(interaction: AutocompleteInteraction) { if (interaction.responded) return; const option = interaction.options.getFocused(true); - const options = CROP_ARRAY.map((v) => ({ name: getCropDisplayName(v), value: v })); + const options = CROP_ARRAY.map((v, i) => ({ + name: getCropDisplayName(v), + value: i.toString(), + })); if (!options) return; const input = option.value.toLowerCase(); diff --git a/src/commands/farm/command.ts b/src/commands/farm/command.ts index d69012f..650500f 100644 --- a/src/commands/farm/command.ts +++ b/src/commands/farm/command.ts @@ -2,7 +2,7 @@ import { CommandAccess, CommandGroup, CommandType } from '../../classes/commands const command = new CommandGroup({ name: 'farm', - description: '', + description: 'hjskadhksaj', execute: () => undefined, access: CommandAccess.Everywhere, type: CommandType.Group, diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index 77d5c77..b5bf539 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -7,7 +7,6 @@ import { ButtonBuilder, ButtonStyle, ChatInputCommandInteraction, - ComponentBuilder, MessageActionRowComponentBuilder, StringSelectMenuBuilder, StringSelectMenuOptionBuilder, @@ -45,7 +44,10 @@ async function autocomplete(interaction: AutocompleteInteraction) { if (interaction.responded) return; const option = interaction.options.getFocused(true); - const options = farmDesigns.map(([key, data]) => ({ name: data.name, value: key })); + const options = farmDesigns.map(([key, data]) => ({ + name: data.name, + value: key, + })); if (!options) return; const input = option.value.toLowerCase(); diff --git a/src/commands/farm/search.ts b/src/commands/farm/search.ts index 059acf0..9c5680d 100644 --- a/src/commands/farm/search.ts +++ b/src/commands/farm/search.ts @@ -1,10 +1,11 @@ import { UserSettings } from 'api/elite.js'; import { eliteCropOption } from 'autocomplete/crops.js'; +import { CROP_ARRAY } from 'classes/Util.js'; import { CommandAccess, CommandType, EliteCommand, SlashCommandOptionType } from 'classes/commands/index.js'; import { EliteContainer } from 'classes/components.js'; import { NotYoursReply } from 'classes/embeds.js'; import { ButtonBuilder, ButtonStyle, ChatInputCommandInteraction, MessageFlags, SectionBuilder } from 'discord.js'; -import { Crop, farmsData, getCropDisplayName, getCropFromName } from 'farming-weight'; +import { Crop, farmsData, getCropDisplayName } from 'farming-weight'; import { execute as farmInfoCommand } from './info.js'; const command = new EliteCommand({ @@ -24,8 +25,7 @@ export default command; async function execute(interaction: ChatInputCommandInteraction, settings?: UserSettings) { await interaction.deferReply(); - const crop = interaction.options.getString('crop', false) as Crop; - if (!crop) return; + const crop = CROP_ARRAY[parseInt(interaction.options.getString('crop', false)!)]; const farms = Object.fromEntries( Object.entries(farmsData) From 92e728a42d3c47ae02e5a27b39566ae5cc8cda50 Mon Sep 17 00:00:00 2001 From: Kaeso <24925519+ptlthg@users.noreply.github.com> Date: Fri, 20 Jun 2025 23:58:45 -0400 Subject: [PATCH 32/61] Support autocomplete in subcommands --- src/events/interactionCreate.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/events/interactionCreate.ts b/src/events/interactionCreate.ts index 9df23fb..1ec5b63 100644 --- a/src/events/interactionCreate.ts +++ b/src/events/interactionCreate.ts @@ -98,9 +98,13 @@ async function OnAutocompleteInteraction(interaction: AutocompleteInteraction) { if (interaction.responded) return; const command = GetCommand(interaction.commandName); - if (!command || command instanceof CommandGroup) return; + if (!command) return; try { + if (command instanceof CommandGroup) { + await command.autocomplete(interaction); + return; + } const auto = command.getAutocomplete(interaction); await auto?.(interaction); } catch (error) { From 14ab0f7bee2e51b6e875a7771d547d11dbbe9f70 Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Fri, 20 Jun 2025 22:19:17 -0700 Subject: [PATCH 33/61] format --- src/autocomplete/crops.ts | 2 +- src/commands/farm/info.ts | 4 ++-- src/commands/farm/search.ts | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/autocomplete/crops.ts b/src/autocomplete/crops.ts index b1acaff..ce9b873 100644 --- a/src/autocomplete/crops.ts +++ b/src/autocomplete/crops.ts @@ -1,5 +1,5 @@ -import { CROP_ARRAY } from 'classes/Util.js'; import { EliteSlashCommandOption, SlashCommandOptionType } from 'classes/commands/options.js'; +import { CROP_ARRAY } from 'classes/Util.js'; import { AutocompleteInteraction } from 'discord.js'; import { getCropDisplayName } from 'farming-weight'; diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index b5bf539..eea831c 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -15,11 +15,11 @@ import { DepthStriderLevels, Direction, FarmingMethod, - MinecraftVersion, - ResourceType, farmDesigns, farmInfo, farmsData, + MinecraftVersion, + ResourceType, } from 'farming-weight'; const command = new EliteCommand({ diff --git a/src/commands/farm/search.ts b/src/commands/farm/search.ts index 9c5680d..e01bc9d 100644 --- a/src/commands/farm/search.ts +++ b/src/commands/farm/search.ts @@ -1,11 +1,11 @@ import { UserSettings } from 'api/elite.js'; import { eliteCropOption } from 'autocomplete/crops.js'; -import { CROP_ARRAY } from 'classes/Util.js'; -import { CommandAccess, CommandType, EliteCommand, SlashCommandOptionType } from 'classes/commands/index.js'; +import { CommandAccess, CommandType, EliteCommand } from 'classes/commands/index.js'; import { EliteContainer } from 'classes/components.js'; import { NotYoursReply } from 'classes/embeds.js'; +import { CROP_ARRAY } from 'classes/Util.js'; import { ButtonBuilder, ButtonStyle, ChatInputCommandInteraction, MessageFlags, SectionBuilder } from 'discord.js'; -import { Crop, farmsData, getCropDisplayName } from 'farming-weight'; +import { farmsData, getCropDisplayName } from 'farming-weight'; import { execute as farmInfoCommand } from './info.js'; const command = new EliteCommand({ From 6e006ca9de5363dd4b1a84403bd3dfb79f707c7a Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Fri, 20 Jun 2025 22:19:25 -0700 Subject: [PATCH 34/61] fix seperator --- src/commands/farm/search.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/farm/search.ts b/src/commands/farm/search.ts index e01bc9d..fb7277a 100644 --- a/src/commands/farm/search.ts +++ b/src/commands/farm/search.ts @@ -36,7 +36,7 @@ async function execute(interaction: ChatInputCommandInteraction, settings?: User const component = new EliteContainer(settings).addTitle(`# Farm designs for ${getCropDisplayName(crop)}`); Object.entries(farms).forEach(([id, data], i) => { - if (i !== 1) { + if (i !== 0) { component.addSeparator(); } From c45997ca92f06e10449a7d2ae81064cf79b2fa1e Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Fri, 20 Jun 2025 22:57:46 -0700 Subject: [PATCH 35/61] fix reply --- src/commands/farm/info.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index eea831c..e8e6530 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -8,6 +8,7 @@ import { ButtonStyle, ChatInputCommandInteraction, MessageActionRowComponentBuilder, + MessageFlags, StringSelectMenuBuilder, StringSelectMenuOptionBuilder, } from 'discord.js'; @@ -76,6 +77,8 @@ export async function execute( settings?: UserSettings, designOverride?: string, ) { + await interaction.deferReply(); + const designId = designOverride ?? interaction.options.getString('design', false) ?? ''; const design = farmsData[designId]; if (!design) return; @@ -161,12 +164,11 @@ export async function execute( components.push(settingsButton); - await interaction - .reply({ - components, - allowedMentions: { repliedUser: false }, - }) - .catch(() => undefined); + const _reply = await interaction.editReply({ + components, + allowedMentions: { repliedUser: false }, + flags: [MessageFlags.IsComponentsV2], + }); } async function calcSpeed( From 794e95272840dcc368666c8318b91b06663f64c8 Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Fri, 20 Jun 2025 22:57:52 -0700 Subject: [PATCH 36/61] fix authors list --- src/commands/farm/info.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index e8e6530..81272ea 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -109,7 +109,17 @@ export async function execute( } if (design.authors) { - farmInfoComponent.addSeparator().addDescription(`-# Authors: ${design.authors.join(', ')}`); + const authors = design.authors + .map((author) => { + if (author.url) { + return `[${author.name}](${author.url})`; + } else { + return author.name; + } + }) + .join(', '); + + farmInfoComponent.addSeparator().addDescription(`-# Authors: ${authors}`); } farmInfoComponent.addFooter(); From da424835a55557072aa5a419dd4ef97a05d1220e Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Fri, 20 Jun 2025 23:37:21 -0700 Subject: [PATCH 37/61] bold stuff --- src/commands/farm/info.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index 81272ea..f4f91f1 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -99,10 +99,16 @@ export async function execute( const farmInfoComponent = new EliteContainer(settings) .addTitle(`# ${design.name}`) .addDescription( - `Yaw: ${yaw}, Pitch: ${design.angle.pitch}\nSpeed: ${speed}, Depth Strider level: ${farmSettings.depthStrider}`, +`**Yaw**: ${yaw}, **Pitch**: ${design.angle.pitch} +**Speed**: ${speed} +**Depth Strider level**: ${farmSettings.depthStrider}`, ) .addSeparator() - .addDescription(`bps: ${design.bps}\nLane time: ${480 / blocksPerSecond}\nKeys used: `); + .addDescription( +`**bps**: ${design.bps} +**Lane time**: ${480 / blocksPerSecond} +**Keys used**: ` + ); if (resources) { farmInfoComponent.addSeparator().addDescription(resources); @@ -119,7 +125,7 @@ export async function execute( }) .join(', '); - farmInfoComponent.addSeparator().addDescription(`-# Authors: ${authors}`); + farmInfoComponent.addSeparator().addDescription(`-# **Authors**: ${authors}`); } farmInfoComponent.addFooter(); @@ -174,7 +180,7 @@ export async function execute( components.push(settingsButton); - const _reply = await interaction.editReply({ + await interaction.editReply({ components, allowedMentions: { repliedUser: false }, flags: [MessageFlags.IsComponentsV2], From 054bbb9078f438f1f9aa657e8e5ccda143188f9d Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Fri, 20 Jun 2025 23:37:34 -0700 Subject: [PATCH 38/61] add no design error embed --- src/commands/farm/info.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index f4f91f1..039f445 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -1,6 +1,7 @@ import { UserSettings } from 'api/elite.js'; import { CommandAccess, CommandType, EliteCommand, SlashCommandOptionType } from 'classes/commands/index.js'; import { EliteContainer } from 'classes/components.js'; +import { ErrorEmbed } from 'classes/embeds.js'; import { ActionRowBuilder, AutocompleteInteraction, @@ -72,6 +73,10 @@ const farmSettings: FarmSettings = { version: '1.8.9', }; +const noDesign = ErrorEmbed('Design Not Found!').setDescription( + "The design you're looking for doesn't exist! If you believe this to be a mistake or want a design added, make a suggestion in the discord.", +); + export async function execute( interaction: ChatInputCommandInteraction, settings?: UserSettings, @@ -81,7 +86,13 @@ export async function execute( const designId = designOverride ?? interaction.options.getString('design', false) ?? ''; const design = farmsData[designId]; - if (!design) return; + if (!design) { + await interaction.editReply({ + embeds: [noDesign], + allowedMentions: { repliedUser: false }, + }); + return; + } const components: (EliteContainer | ActionRowBuilder)[] = []; From f6cf2263307f9b6d9919e9be6ef39b63ca8ca7c1 Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Fri, 20 Jun 2025 23:37:50 -0700 Subject: [PATCH 39/61] fix resources section --- src/commands/farm/info.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index 039f445..1938db8 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -98,7 +98,15 @@ export async function execute( const resources = design.resources ?.filter((r) => r.type !== ResourceType.Schematic) - .map((r) => `${r.type}: ${r.source}`) + .map((r) => { + let source: string; + if (r.type === ResourceType.Garden) { + source = `\`/visit ${r.source}\``; + } else { + source = r.source; + } + return `**${ResourceType[r.type]}**: ${source}`; + }) .join('\n'); const speed = await calcSpeed(design.speed, farmSettings.version, farmSettings.depthStrider); From 4ea151ac2ee8924543aca465bbc1036cbe2ea764 Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Sat, 21 Jun 2025 00:48:23 -0700 Subject: [PATCH 40/61] fix farm search buttons --- src/commands/farm/info.ts | 3 ++- src/commands/farm/search.ts | 4 +--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index 1938db8..26453f5 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -81,8 +81,9 @@ export async function execute( interaction: ChatInputCommandInteraction, settings?: UserSettings, designOverride?: string, + defer?: boolean, ) { - await interaction.deferReply(); + if (defer) await interaction.deferReply(); const designId = designOverride ?? interaction.options.getString('design', false) ?? ''; const design = farmsData[designId]; diff --git a/src/commands/farm/search.ts b/src/commands/farm/search.ts index fb7277a..009742f 100644 --- a/src/commands/farm/search.ts +++ b/src/commands/farm/search.ts @@ -66,9 +66,7 @@ async function execute(interaction: ChatInputCommandInteraction, settings?: User collector.resetTimer(); - await farmInfoCommand(interaction, settings, inter.customId); - - await inter.deleteReply(); + await farmInfoCommand(interaction, settings, inter.customId, false); return; }); From 1d5d26643611d87b3a967eac6c1aaae92b35e481 Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Sat, 21 Jun 2025 00:48:23 -0700 Subject: [PATCH 41/61] fix farm search buttons --- src/commands/farm/info.ts | 3 ++- src/commands/farm/search.ts | 4 +--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index 1938db8..3e53fba 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -81,8 +81,9 @@ export async function execute( interaction: ChatInputCommandInteraction, settings?: UserSettings, designOverride?: string, + skipDefer?: boolean, ) { - await interaction.deferReply(); + if (!skipDefer) await interaction.deferReply(); const designId = designOverride ?? interaction.options.getString('design', false) ?? ''; const design = farmsData[designId]; diff --git a/src/commands/farm/search.ts b/src/commands/farm/search.ts index fb7277a..cbf6b8f 100644 --- a/src/commands/farm/search.ts +++ b/src/commands/farm/search.ts @@ -66,9 +66,7 @@ async function execute(interaction: ChatInputCommandInteraction, settings?: User collector.resetTimer(); - await farmInfoCommand(interaction, settings, inter.customId); - - await inter.deleteReply(); + await farmInfoCommand(interaction, settings, inter.customId, true); return; }); From 1ca6e015e0eca18a372fbcc86a55487ceea904d5 Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Sat, 21 Jun 2025 02:11:25 -0700 Subject: [PATCH 42/61] remove depth strider --- src/commands/farm/info.ts | 38 +++++++++----------------------------- 1 file changed, 9 insertions(+), 29 deletions(-) diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index 3e53fba..133a79a 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -14,7 +14,6 @@ import { StringSelectMenuOptionBuilder, } from 'discord.js'; import { - DepthStriderLevels, Direction, FarmingMethod, farmDesigns, @@ -62,13 +61,11 @@ async function autocomplete(interaction: AutocompleteInteraction) { export default command; interface FarmSettings { - depthStrider: DepthStriderLevels; direction: Direction; version: MinecraftVersion; } const farmSettings: FarmSettings = { - depthStrider: 3, direction: 'East', version: '1.8.9', }; @@ -77,6 +74,12 @@ const noDesign = ErrorEmbed('Design Not Found!').setDescription( "The design you're looking for doesn't exist! If you believe this to be a mistake or want a design added, make a suggestion in the discord.", ); +// todo: fix +const soulSandVersionMultiplier = { + '1.8.9': 0.4, + '1.21': 0.5, +}; + export async function execute( interaction: ChatInputCommandInteraction, settings?: UserSettings, @@ -110,7 +113,7 @@ export async function execute( }) .join('\n'); - const speed = await calcSpeed(design.speed, farmSettings.version, farmSettings.depthStrider); + const speed = await calcSpeed(design.speed, farmSettings.version); const blocksPerSecond = await calcBlocksPerSecond(speed, design.angle.yaw, design.speed.method); @@ -121,7 +124,7 @@ export async function execute( .addDescription( `**Yaw**: ${yaw}, **Pitch**: ${design.angle.pitch} **Speed**: ${speed} -**Depth Strider level**: ${farmSettings.depthStrider}`, +**Depth Strider level**: ${design.speed.depthStrider}`, ) .addSeparator() .addDescription( @@ -154,18 +157,6 @@ export async function execute( const settingsComponent = new EliteContainer(settings) .addTitle('# Settings') - .addActionRowComponents( - new ActionRowBuilder().addComponents( - new StringSelectMenuBuilder() - .setCustomId('depthStrider') - .setPlaceholder('Select the depth strider level you use') - .addOptions( - new StringSelectMenuOptionBuilder().setLabel('Depth Strider 1').setValue('1'), - new StringSelectMenuOptionBuilder().setLabel('Depth Strider 2').setValue('2'), - new StringSelectMenuOptionBuilder().setLabel('Depth Strider 3').setValue('3'), - ), - ), - ) .addActionRowComponents( new ActionRowBuilder().addComponents( new StringSelectMenuBuilder() @@ -210,22 +201,11 @@ export async function execute( async function calcSpeed( designSpeed: farmInfo['speed'], targetVersion?: MinecraftVersion, - targetDepthStrider?: DepthStriderLevels, ): Promise { - // todo: fix - const versionMultiplier = { - '1.8.9': 0.4, - '1.21': 0.5, - }; - let speed = designSpeed.speed; - if (designSpeed.depthStrider && targetDepthStrider) { - speed *= targetDepthStrider / designSpeed.depthStrider; - } - if (designSpeed.soulSand && designSpeed.buildVersion && targetVersion) { - speed *= versionMultiplier[targetVersion] / versionMultiplier[designSpeed.buildVersion]; + speed *= soulSandVersionMultiplier[targetVersion] / soulSandVersionMultiplier[designSpeed.buildVersion]; } return speed; From 65faee076d690475d10e187c0ad5c5231808f81b Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Sat, 21 Jun 2025 02:36:13 -0700 Subject: [PATCH 43/61] remove keys sued, hide depth strider if level isnt speciified --- src/commands/farm/info.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index 133a79a..5ed7929 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -123,14 +123,12 @@ export async function execute( .addTitle(`# ${design.name}`) .addDescription( `**Yaw**: ${yaw}, **Pitch**: ${design.angle.pitch} -**Speed**: ${speed} -**Depth Strider level**: ${design.speed.depthStrider}`, +**Speed**: ${speed}${design.speed.depthStrider ? `\n**Depth Strider level**: ${design.speed.depthStrider}` : ''}`, ) .addSeparator() .addDescription( `**bps**: ${design.bps} -**Lane time**: ${480 / blocksPerSecond} -**Keys used**: ` +**Lane time**: ${480 / blocksPerSecond}` ); if (resources) { From 5cbb3ea96c06375464a6590d0cafcc7b392e2832 Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Sat, 21 Jun 2025 13:02:50 -0700 Subject: [PATCH 44/61] command group description --- src/commands/farm/command.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/farm/command.ts b/src/commands/farm/command.ts index 650500f..3f24f19 100644 --- a/src/commands/farm/command.ts +++ b/src/commands/farm/command.ts @@ -2,7 +2,7 @@ import { CommandAccess, CommandGroup, CommandType } from '../../classes/commands const command = new CommandGroup({ name: 'farm', - description: 'hjskadhksaj', + description: 'Commands to view farm designs', execute: () => undefined, access: CommandAccess.Everywhere, type: CommandType.Group, From 8ec27e27d376e01462aa63a688665fd7afef0ebd Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Sat, 21 Jun 2025 13:52:43 -0700 Subject: [PATCH 45/61] begin button/menu collector stuff --- src/commands/farm/info.ts | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index 5ed7929..eeec4b5 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -1,7 +1,7 @@ import { UserSettings } from 'api/elite.js'; import { CommandAccess, CommandType, EliteCommand, SlashCommandOptionType } from 'classes/commands/index.js'; import { EliteContainer } from 'classes/components.js'; -import { ErrorEmbed } from 'classes/embeds.js'; +import { ErrorEmbed, NotYoursReply } from 'classes/embeds.js'; import { ActionRowBuilder, AutocompleteInteraction, @@ -66,7 +66,7 @@ interface FarmSettings { } const farmSettings: FarmSettings = { - direction: 'East', + direction: 'South', version: '1.8.9', }; @@ -90,7 +90,10 @@ export async function execute( const designId = designOverride ?? interaction.options.getString('design', false) ?? ''; const design = farmsData[designId]; + console.log(design) + if (!design) { + // console.log('test\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\n') await interaction.editReply({ embeds: [noDesign], allowedMentions: { repliedUser: false }, @@ -189,11 +192,29 @@ export async function execute( components.push(settingsButton); - await interaction.editReply({ + const reply = await interaction.editReply({ components, allowedMentions: { repliedUser: false }, flags: [MessageFlags.IsComponentsV2], }); + + const collector = reply.createMessageComponentCollector({ + time: 120_000, + }); + + collector.on('collect', async (inter) => { + if (inter.user.id !== interaction.user.id) { + return NotYoursReply(inter); + } + + collector.resetTimer(); + + if (inter.isStringSelectMenu()) { + console.log(inter.customId + '\t' + inter.values.join(', ')); + } + + return; + }); } async function calcSpeed( From ed3b7e605ba43f6e1686c6f6deefe61dbd8ca3fb Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Sat, 21 Jun 2025 14:49:36 -0700 Subject: [PATCH 46/61] fix design being undefined --- src/commands/farm/info.ts | 7 +++---- src/commands/farm/search.ts | 2 ++ 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index eeec4b5..c035267 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -90,7 +90,6 @@ export async function execute( const designId = designOverride ?? interaction.options.getString('design', false) ?? ''; const design = farmsData[designId]; - console.log(design) if (!design) { // console.log('test\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\n') @@ -161,7 +160,7 @@ export async function execute( .addActionRowComponents( new ActionRowBuilder().addComponents( new StringSelectMenuBuilder() - .setCustomId('direction') + .setCustomId('design-direction') .setPlaceholder('Select the direction your farm faces') .addOptions( new StringSelectMenuOptionBuilder().setLabel('North').setValue('North'), @@ -174,7 +173,7 @@ export async function execute( .addActionRowComponents( new ActionRowBuilder().addComponents( new StringSelectMenuBuilder() - .setCustomId('version') + .setCustomId('design-version') .setPlaceholder('Select Minecaft version') .addOptions( new StringSelectMenuOptionBuilder().setLabel('1.8.9').setValue('1.8.9').setDefault(true), @@ -187,7 +186,7 @@ export async function execute( components.push(settingsComponent); const settingsButton = new ActionRowBuilder().addComponents( - new ButtonBuilder().setStyle(ButtonStyle.Secondary).setLabel('Open Settings').setCustomId('settings'), + new ButtonBuilder().setStyle(ButtonStyle.Secondary).setLabel('Open Settings').setCustomId('design-settings'), ); components.push(settingsButton); diff --git a/src/commands/farm/search.ts b/src/commands/farm/search.ts index cbf6b8f..758b0cb 100644 --- a/src/commands/farm/search.ts +++ b/src/commands/farm/search.ts @@ -68,6 +68,8 @@ async function execute(interaction: ChatInputCommandInteraction, settings?: User await farmInfoCommand(interaction, settings, inter.customId, true); + collector.stop(); + return; }); } From a913e5aa2fb5bde4ac9ece0e5e1ae6c596b0ef6b Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Sat, 21 Jun 2025 15:09:28 -0700 Subject: [PATCH 47/61] update embed for direction --- src/commands/farm/info.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index c035267..44f1da9 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -206,10 +206,19 @@ export async function execute( return NotYoursReply(inter); } + inter.deferReply(); + collector.resetTimer(); if (inter.isStringSelectMenu()) { console.log(inter.customId + '\t' + inter.values.join(', ')); + + if (inter.customId === "design-direction") { + farmSettings.direction = inter.values[0] as Direction; + await execute(interaction, settings, undefined, true); + inter.deleteReply(); + collector.stop(); + } } return; From 80ec63c9ca39ff30e4d523ce56a2a9c7f68ee816 Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Sat, 21 Jun 2025 16:11:25 -0700 Subject: [PATCH 48/61] refactor components and make settigns work --- src/commands/farm/info.ts | 149 ++++++++++++++++++++++---------------- 1 file changed, 86 insertions(+), 63 deletions(-) diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index 44f1da9..de1de00 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -61,11 +61,13 @@ async function autocomplete(interaction: AutocompleteInteraction) { export default command; interface FarmSettings { + active: boolean; direction: Direction; version: MinecraftVersion; } const farmSettings: FarmSettings = { + active: true, direction: 'South', version: '1.8.9', }; @@ -92,7 +94,6 @@ export async function execute( const design = farmsData[designId]; if (!design) { - // console.log('test\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\n') await interaction.editReply({ embeds: [noDesign], allowedMentions: { repliedUser: false }, @@ -100,6 +101,57 @@ export async function execute( return; } + const components = await getFarmInfoComponents(design, settings); + + const reply = await interaction.editReply({ + components, + allowedMentions: { repliedUser: false }, + flags: [MessageFlags.IsComponentsV2], + }); + + const collector = reply.createMessageComponentCollector({ + time: 120_000, + }); + + collector.on('collect', async (inter) => { + if (inter.user.id !== interaction.user.id) { + return NotYoursReply(inter); + } + + await inter.deferReply(); + + collector.resetTimer(); + + if (inter.isStringSelectMenu()) { + if (inter.customId === "design-direction") { + farmSettings.direction = inter.values[0] as Direction; + } else if (inter.customId === "design-version") { + farmSettings.version = inter.values[0] as MinecraftVersion; + } + } else if (inter.isButton()) { + if (inter.customId === "design-settings") { + farmSettings.active = !farmSettings.active; + } + } + + const components = await getFarmInfoComponents(design, settings); + + await interaction.editReply({ + components, + allowedMentions: { repliedUser: false }, + flags: [MessageFlags.IsComponentsV2], + }); + + await inter.deleteReply(); + + return; + }); +} + +async function getFarmInfoComponents( + design: farmInfo, + settings?: UserSettings, +): Promise<(EliteContainer | ActionRowBuilder)[]> { const components: (EliteContainer | ActionRowBuilder)[] = []; const resources = design.resources @@ -155,74 +207,45 @@ export async function execute( components.push(farmInfoComponent); - const settingsComponent = new EliteContainer(settings) - .addTitle('# Settings') - .addActionRowComponents( - new ActionRowBuilder().addComponents( - new StringSelectMenuBuilder() - .setCustomId('design-direction') - .setPlaceholder('Select the direction your farm faces') - .addOptions( - new StringSelectMenuOptionBuilder().setLabel('North').setValue('North'), - new StringSelectMenuOptionBuilder().setLabel('South').setValue('South'), - new StringSelectMenuOptionBuilder().setLabel('East').setValue('East'), - new StringSelectMenuOptionBuilder().setLabel('West').setValue('West'), - ), - ), - ) - .addActionRowComponents( - new ActionRowBuilder().addComponents( - new StringSelectMenuBuilder() - .setCustomId('design-version') - .setPlaceholder('Select Minecaft version') - .addOptions( - new StringSelectMenuOptionBuilder().setLabel('1.8.9').setValue('1.8.9').setDefault(true), - new StringSelectMenuOptionBuilder().setLabel('1.21').setValue('1.21'), - ), - ), - ) - .addFooter(); - - components.push(settingsComponent); + if (farmSettings.active) { + const settingsComponent = new EliteContainer(settings) + .addTitle('# Settings') + .addActionRowComponents( + new ActionRowBuilder().addComponents( + new StringSelectMenuBuilder() + .setCustomId('design-direction') + .setPlaceholder('Select the direction your farm faces') + .addOptions( + new StringSelectMenuOptionBuilder().setLabel('North').setValue('North').setDefault(farmSettings.direction == 'North'), + new StringSelectMenuOptionBuilder().setLabel('South').setValue('South').setDefault(farmSettings.direction == 'South'), + new StringSelectMenuOptionBuilder().setLabel('East').setValue('East').setDefault(farmSettings.direction == 'East'), + new StringSelectMenuOptionBuilder().setLabel('West').setValue('West').setDefault(farmSettings.direction == 'West'), + ), + ), + ) + .addActionRowComponents( + new ActionRowBuilder().addComponents( + new StringSelectMenuBuilder() + .setCustomId('design-version') + .setPlaceholder('Select Minecaft version') + .addOptions( + new StringSelectMenuOptionBuilder().setLabel('1.8.9').setValue('1.8.9').setDefault(farmSettings.version == '1.8.9'), + new StringSelectMenuOptionBuilder().setLabel('1.21').setValue('1.21').setDefault(farmSettings.version == '1.21'), + ), + ), + ) + .addFooter(); + + components.push(settingsComponent); + } const settingsButton = new ActionRowBuilder().addComponents( - new ButtonBuilder().setStyle(ButtonStyle.Secondary).setLabel('Open Settings').setCustomId('design-settings'), + new ButtonBuilder().setStyle(ButtonStyle.Secondary).setLabel(`${farmSettings.active ? 'Close' : 'Open'} Settings`).setCustomId('design-settings'), ); components.push(settingsButton); - const reply = await interaction.editReply({ - components, - allowedMentions: { repliedUser: false }, - flags: [MessageFlags.IsComponentsV2], - }); - - const collector = reply.createMessageComponentCollector({ - time: 120_000, - }); - - collector.on('collect', async (inter) => { - if (inter.user.id !== interaction.user.id) { - return NotYoursReply(inter); - } - - inter.deferReply(); - - collector.resetTimer(); - - if (inter.isStringSelectMenu()) { - console.log(inter.customId + '\t' + inter.values.join(', ')); - - if (inter.customId === "design-direction") { - farmSettings.direction = inter.values[0] as Direction; - await execute(interaction, settings, undefined, true); - inter.deleteReply(); - collector.stop(); - } - } - - return; - }); + return components } async function calcSpeed( From 042ac121dcf726564554241e0c28575b80ad2bd2 Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Sat, 21 Jun 2025 16:24:02 -0700 Subject: [PATCH 49/61] lint --- src/commands/farm/info.ts | 68 +++++++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 25 deletions(-) diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index de1de00..0578057 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -123,26 +123,26 @@ export async function execute( collector.resetTimer(); if (inter.isStringSelectMenu()) { - if (inter.customId === "design-direction") { + if (inter.customId === 'design-direction') { farmSettings.direction = inter.values[0] as Direction; - } else if (inter.customId === "design-version") { + } else if (inter.customId === 'design-version') { farmSettings.version = inter.values[0] as MinecraftVersion; } } else if (inter.isButton()) { - if (inter.customId === "design-settings") { + if (inter.customId === 'design-settings') { farmSettings.active = !farmSettings.active; } } - const components = await getFarmInfoComponents(design, settings); + const components = await getFarmInfoComponents(design, settings); - await interaction.editReply({ - components, - allowedMentions: { repliedUser: false }, - flags: [MessageFlags.IsComponentsV2], - }); + await interaction.editReply({ + components, + allowedMentions: { repliedUser: false }, + flags: [MessageFlags.IsComponentsV2], + }); - await inter.deleteReply(); + await inter.deleteReply(); return; }); @@ -176,13 +176,13 @@ async function getFarmInfoComponents( const farmInfoComponent = new EliteContainer(settings) .addTitle(`# ${design.name}`) .addDescription( -`**Yaw**: ${yaw}, **Pitch**: ${design.angle.pitch} + `**Yaw**: ${yaw}, **Pitch**: ${design.angle.pitch} **Speed**: ${speed}${design.speed.depthStrider ? `\n**Depth Strider level**: ${design.speed.depthStrider}` : ''}`, ) .addSeparator() .addDescription( -`**bps**: ${design.bps} -**Lane time**: ${480 / blocksPerSecond}` + `**bps**: ${design.bps} +**Lane time**: ${480 / blocksPerSecond}`, ); if (resources) { @@ -216,10 +216,22 @@ async function getFarmInfoComponents( .setCustomId('design-direction') .setPlaceholder('Select the direction your farm faces') .addOptions( - new StringSelectMenuOptionBuilder().setLabel('North').setValue('North').setDefault(farmSettings.direction == 'North'), - new StringSelectMenuOptionBuilder().setLabel('South').setValue('South').setDefault(farmSettings.direction == 'South'), - new StringSelectMenuOptionBuilder().setLabel('East').setValue('East').setDefault(farmSettings.direction == 'East'), - new StringSelectMenuOptionBuilder().setLabel('West').setValue('West').setDefault(farmSettings.direction == 'West'), + new StringSelectMenuOptionBuilder() + .setLabel('North') + .setValue('North') + .setDefault(farmSettings.direction == 'North'), + new StringSelectMenuOptionBuilder() + .setLabel('South') + .setValue('South') + .setDefault(farmSettings.direction == 'South'), + new StringSelectMenuOptionBuilder() + .setLabel('East') + .setValue('East') + .setDefault(farmSettings.direction == 'East'), + new StringSelectMenuOptionBuilder() + .setLabel('West') + .setValue('West') + .setDefault(farmSettings.direction == 'West'), ), ), ) @@ -229,8 +241,14 @@ async function getFarmInfoComponents( .setCustomId('design-version') .setPlaceholder('Select Minecaft version') .addOptions( - new StringSelectMenuOptionBuilder().setLabel('1.8.9').setValue('1.8.9').setDefault(farmSettings.version == '1.8.9'), - new StringSelectMenuOptionBuilder().setLabel('1.21').setValue('1.21').setDefault(farmSettings.version == '1.21'), + new StringSelectMenuOptionBuilder() + .setLabel('1.8.9') + .setValue('1.8.9') + .setDefault(farmSettings.version == '1.8.9'), + new StringSelectMenuOptionBuilder() + .setLabel('1.21') + .setValue('1.21') + .setDefault(farmSettings.version == '1.21'), ), ), ) @@ -240,18 +258,18 @@ async function getFarmInfoComponents( } const settingsButton = new ActionRowBuilder().addComponents( - new ButtonBuilder().setStyle(ButtonStyle.Secondary).setLabel(`${farmSettings.active ? 'Close' : 'Open'} Settings`).setCustomId('design-settings'), + new ButtonBuilder() + .setStyle(ButtonStyle.Secondary) + .setLabel(`${farmSettings.active ? 'Close' : 'Open'} Settings`) + .setCustomId('design-settings'), ); components.push(settingsButton); - return components + return components; } -async function calcSpeed( - designSpeed: farmInfo['speed'], - targetVersion?: MinecraftVersion, -): Promise { +async function calcSpeed(designSpeed: farmInfo['speed'], targetVersion?: MinecraftVersion): Promise { let speed = designSpeed.speed; if (designSpeed.soulSand && designSpeed.buildVersion && targetVersion) { From 4a5d84f2b1149ee90bd21163486bf929210fa716 Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Sat, 21 Jun 2025 16:50:58 -0700 Subject: [PATCH 50/61] fix soul sand speeds --- src/commands/farm/info.ts | 31 ++++++------------------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index 0578057..a7c0505 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -76,12 +76,6 @@ const noDesign = ErrorEmbed('Design Not Found!').setDescription( "The design you're looking for doesn't exist! If you believe this to be a mistake or want a design added, make a suggestion in the discord.", ); -// todo: fix -const soulSandVersionMultiplier = { - '1.8.9': 0.4, - '1.21': 0.5, -}; - export async function execute( interaction: ChatInputCommandInteraction, settings?: UserSettings, @@ -167,23 +161,19 @@ async function getFarmInfoComponents( }) .join('\n'); - const speed = await calcSpeed(design.speed, farmSettings.version); + const speed = design.speed.soulSand ? design.speed[farmSettings.version] : design.speed['1.8.9']; - const blocksPerSecond = await calcBlocksPerSecond(speed, design.angle.yaw, design.speed.method); + const blocksPerSecond = await calcBlocksPerSecond(design.angle.yaw, design.speed.method, speed); const yaw = await fixDesignAngle(design.angle.yaw, farmSettings.direction); const farmInfoComponent = new EliteContainer(settings) .addTitle(`# ${design.name}`) .addDescription( - `**Yaw**: ${yaw}, **Pitch**: ${design.angle.pitch} -**Speed**: ${speed}${design.speed.depthStrider ? `\n**Depth Strider level**: ${design.speed.depthStrider}` : ''}`, + `**Yaw**: ${yaw}, **Pitch**: ${design.angle.pitch}\n**Speed**: ${speed ?? '1.21 speed has not yet been determined'}${design.speed.depthStrider ? `\n**Depth Strider level**: ${design.speed.depthStrider}` : ''}`, ) .addSeparator() - .addDescription( - `**bps**: ${design.bps} -**Lane time**: ${480 / blocksPerSecond}`, - ); + .addDescription(`**bps**: ${design.bps}${blocksPerSecond ? `\n**Lane time**: ${480 / blocksPerSecond}` : ''}`); if (resources) { farmInfoComponent.addSeparator().addDescription(resources); @@ -269,17 +259,8 @@ async function getFarmInfoComponents( return components; } -async function calcSpeed(designSpeed: farmInfo['speed'], targetVersion?: MinecraftVersion): Promise { - let speed = designSpeed.speed; - - if (designSpeed.soulSand && designSpeed.buildVersion && targetVersion) { - speed *= soulSandVersionMultiplier[targetVersion] / soulSandVersionMultiplier[designSpeed.buildVersion]; - } - - return speed; -} - -async function calcBlocksPerSecond(speed: number, yaw: number, method: FarmingMethod): Promise { +async function calcBlocksPerSecond(yaw: number, method: FarmingMethod, speed?: number): Promise { + if (!speed) return undefined; if (method === 'running into wall' && yaw === 0) { speed *= 1.02042464775; yaw = 45; From 0cbac1bee1c540e3f9e9df8a28f894fd42f9b9b3 Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Sat, 21 Jun 2025 16:53:10 -0700 Subject: [PATCH 51/61] make farm settings command based rather than global --- src/commands/farm/info.ts | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index a7c0505..938d3f9 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -66,12 +66,6 @@ interface FarmSettings { version: MinecraftVersion; } -const farmSettings: FarmSettings = { - active: true, - direction: 'South', - version: '1.8.9', -}; - const noDesign = ErrorEmbed('Design Not Found!').setDescription( "The design you're looking for doesn't exist! If you believe this to be a mistake or want a design added, make a suggestion in the discord.", ); @@ -84,6 +78,12 @@ export async function execute( ) { if (!skipDefer) await interaction.deferReply(); + const farmSettings: FarmSettings = { + active: true, + direction: 'South', + version: '1.8.9', + }; + const designId = designOverride ?? interaction.options.getString('design', false) ?? ''; const design = farmsData[designId]; @@ -95,7 +95,7 @@ export async function execute( return; } - const components = await getFarmInfoComponents(design, settings); + const components = await getFarmInfoComponents(design, farmSettings, settings); const reply = await interaction.editReply({ components, @@ -128,7 +128,7 @@ export async function execute( } } - const components = await getFarmInfoComponents(design, settings); + const components = await getFarmInfoComponents(design, farmSettings, settings); await interaction.editReply({ components, @@ -144,6 +144,7 @@ export async function execute( async function getFarmInfoComponents( design: farmInfo, + farmSettings: FarmSettings, settings?: UserSettings, ): Promise<(EliteContainer | ActionRowBuilder)[]> { const components: (EliteContainer | ActionRowBuilder)[] = []; From a1a2ebf071c43ed69e77386bc3625648626ed69a Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Sat, 21 Jun 2025 17:07:54 -0700 Subject: [PATCH 52/61] update imports for docker --- src/commands/farm/info.ts | 8 ++++---- src/commands/farm/search.ts | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index 938d3f9..141d4d0 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -1,7 +1,3 @@ -import { UserSettings } from 'api/elite.js'; -import { CommandAccess, CommandType, EliteCommand, SlashCommandOptionType } from 'classes/commands/index.js'; -import { EliteContainer } from 'classes/components.js'; -import { ErrorEmbed, NotYoursReply } from 'classes/embeds.js'; import { ActionRowBuilder, AutocompleteInteraction, @@ -22,6 +18,10 @@ import { MinecraftVersion, ResourceType, } from 'farming-weight'; +import { UserSettings } from '../../api/elite.js'; +import { CommandAccess, CommandType, EliteCommand, SlashCommandOptionType } from '../../classes/commands/index.js'; +import { EliteContainer } from '../../classes/components.js'; +import { ErrorEmbed, NotYoursReply } from '../../classes/embeds.js'; const command = new EliteCommand({ name: 'info', diff --git a/src/commands/farm/search.ts b/src/commands/farm/search.ts index 758b0cb..73ecbfc 100644 --- a/src/commands/farm/search.ts +++ b/src/commands/farm/search.ts @@ -1,11 +1,11 @@ -import { UserSettings } from 'api/elite.js'; -import { eliteCropOption } from 'autocomplete/crops.js'; -import { CommandAccess, CommandType, EliteCommand } from 'classes/commands/index.js'; -import { EliteContainer } from 'classes/components.js'; -import { NotYoursReply } from 'classes/embeds.js'; -import { CROP_ARRAY } from 'classes/Util.js'; import { ButtonBuilder, ButtonStyle, ChatInputCommandInteraction, MessageFlags, SectionBuilder } from 'discord.js'; import { farmsData, getCropDisplayName } from 'farming-weight'; +import { UserSettings } from '../../api/elite.js'; +import { eliteCropOption } from '../../autocomplete/crops.js'; +import { CommandAccess, CommandType, EliteCommand } from '../../classes/commands/index.js'; +import { EliteContainer } from '../../classes/components.js'; +import { NotYoursReply } from '../../classes/embeds.js'; +import { CROP_ARRAY } from '../../classes/Util.js'; import { execute as farmInfoCommand } from './info.js'; const command = new EliteCommand({ From d6e882eaea7cc567f7d6cc220f1d81d760070673 Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Sat, 21 Jun 2025 17:12:21 -0700 Subject: [PATCH 53/61] update variable names --- src/commands/farm/info.ts | 26 +++++++++----------------- src/commands/farm/search.ts | 4 ++-- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index 141d4d0..922a258 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -9,15 +9,7 @@ import { StringSelectMenuBuilder, StringSelectMenuOptionBuilder, } from 'discord.js'; -import { - Direction, - FarmingMethod, - farmDesigns, - farmInfo, - farmsData, - MinecraftVersion, - ResourceType, -} from 'farming-weight'; +import { Direction, FARM_DESIGNS, FarmDesignInfo, FarmingMethod, MinecraftVersion, ResourceType } from 'farming-weight'; import { UserSettings } from '../../api/elite.js'; import { CommandAccess, CommandType, EliteCommand, SlashCommandOptionType } from '../../classes/commands/index.js'; import { EliteContainer } from '../../classes/components.js'; @@ -45,7 +37,7 @@ async function autocomplete(interaction: AutocompleteInteraction) { if (interaction.responded) return; const option = interaction.options.getFocused(true); - const options = farmDesigns.map(([key, data]) => ({ + const options = Object.entries(FARM_DESIGNS).map(([key, data]) => ({ name: data.name, value: key, })); @@ -85,7 +77,7 @@ export async function execute( }; const designId = designOverride ?? interaction.options.getString('design', false) ?? ''; - const design = farmsData[designId]; + const design = FARM_DESIGNS[designId]; if (!design) { await interaction.editReply({ @@ -143,7 +135,7 @@ export async function execute( } async function getFarmInfoComponents( - design: farmInfo, + design: FarmDesignInfo, farmSettings: FarmSettings, settings?: UserSettings, ): Promise<(EliteContainer | ActionRowBuilder)[]> { @@ -168,7 +160,7 @@ async function getFarmInfoComponents( const yaw = await fixDesignAngle(design.angle.yaw, farmSettings.direction); - const farmInfoComponent = new EliteContainer(settings) + const FarmDesignInfoComponent = new EliteContainer(settings) .addTitle(`# ${design.name}`) .addDescription( `**Yaw**: ${yaw}, **Pitch**: ${design.angle.pitch}\n**Speed**: ${speed ?? '1.21 speed has not yet been determined'}${design.speed.depthStrider ? `\n**Depth Strider level**: ${design.speed.depthStrider}` : ''}`, @@ -177,7 +169,7 @@ async function getFarmInfoComponents( .addDescription(`**bps**: ${design.bps}${blocksPerSecond ? `\n**Lane time**: ${480 / blocksPerSecond}` : ''}`); if (resources) { - farmInfoComponent.addSeparator().addDescription(resources); + FarmDesignInfoComponent.addSeparator().addDescription(resources); } if (design.authors) { @@ -191,12 +183,12 @@ async function getFarmInfoComponents( }) .join(', '); - farmInfoComponent.addSeparator().addDescription(`-# **Authors**: ${authors}`); + FarmDesignInfoComponent.addSeparator().addDescription(`-# **Authors**: ${authors}`); } - farmInfoComponent.addFooter(); + FarmDesignInfoComponent.addFooter(); - components.push(farmInfoComponent); + components.push(FarmDesignInfoComponent); if (farmSettings.active) { const settingsComponent = new EliteContainer(settings) diff --git a/src/commands/farm/search.ts b/src/commands/farm/search.ts index 73ecbfc..0c2d29b 100644 --- a/src/commands/farm/search.ts +++ b/src/commands/farm/search.ts @@ -1,5 +1,5 @@ import { ButtonBuilder, ButtonStyle, ChatInputCommandInteraction, MessageFlags, SectionBuilder } from 'discord.js'; -import { farmsData, getCropDisplayName } from 'farming-weight'; +import { FARM_DESIGNS, getCropDisplayName } from 'farming-weight'; import { UserSettings } from '../../api/elite.js'; import { eliteCropOption } from '../../autocomplete/crops.js'; import { CommandAccess, CommandType, EliteCommand } from '../../classes/commands/index.js'; @@ -28,7 +28,7 @@ async function execute(interaction: ChatInputCommandInteraction, settings?: User const crop = CROP_ARRAY[parseInt(interaction.options.getString('crop', false)!)]; const farms = Object.fromEntries( - Object.entries(farmsData) + Object.entries(FARM_DESIGNS) .filter(([, farm]) => farm.crops.includes(crop)) .sort(([, a], [, b]) => b.bps - a.bps), ); From d51ebc801944443cabe61fb2db076a1f863d9cd9 Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Sat, 21 Jun 2025 17:30:17 -0700 Subject: [PATCH 54/61] add replaced by section --- src/commands/farm/info.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index 922a258..1e48ac5 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -154,6 +154,12 @@ async function getFarmInfoComponents( }) .join('\n'); + const replacedBy = design.replacedBy + ?.map((d) => { + return FARM_DESIGNS[d].name; + }) + .join('\n'); + const speed = design.speed.soulSand ? design.speed[farmSettings.version] : design.speed['1.8.9']; const blocksPerSecond = await calcBlocksPerSecond(design.angle.yaw, design.speed.method, speed); @@ -168,6 +174,10 @@ async function getFarmInfoComponents( .addSeparator() .addDescription(`**bps**: ${design.bps}${blocksPerSecond ? `\n**Lane time**: ${480 / blocksPerSecond}` : ''}`); + if (replacedBy) { + FarmDesignInfoComponent.addSeparator().addDescription(`**Design is outdated, use one of these**:\n${replacedBy}`); + } + if (resources) { FarmDesignInfoComponent.addSeparator().addDescription(resources); } From 625b48a647d768b1df0024b858e9fd41bcd2f0f0 Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Sat, 21 Jun 2025 17:32:39 -0700 Subject: [PATCH 55/61] add notes section --- src/commands/farm/info.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index 1e48ac5..8b11c11 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -182,6 +182,10 @@ async function getFarmInfoComponents( FarmDesignInfoComponent.addSeparator().addDescription(resources); } + if (design.notes) { + FarmDesignInfoComponent.addSeparator().addDescription(design.notes.join('\n')); + } + if (design.authors) { const authors = design.authors .map((author) => { From 86b75b235d2ebad6889ef9e0ed501ebdf5832a14 Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Sat, 21 Jun 2025 17:52:41 -0700 Subject: [PATCH 56/61] fix lane time --- src/commands/farm/info.ts | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index 8b11c11..d2c33c7 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -9,7 +9,7 @@ import { StringSelectMenuBuilder, StringSelectMenuOptionBuilder, } from 'discord.js'; -import { Direction, FARM_DESIGNS, FarmDesignInfo, FarmingMethod, MinecraftVersion, ResourceType } from 'farming-weight'; +import { Direction, FARM_DESIGNS, FarmDesignInfo, MinecraftVersion, ResourceType } from 'farming-weight'; import { UserSettings } from '../../api/elite.js'; import { CommandAccess, CommandType, EliteCommand, SlashCommandOptionType } from '../../classes/commands/index.js'; import { EliteContainer } from '../../classes/components.js'; @@ -162,17 +162,21 @@ async function getFarmInfoComponents( const speed = design.speed.soulSand ? design.speed[farmSettings.version] : design.speed['1.8.9']; - const blocksPerSecond = await calcBlocksPerSecond(design.angle.yaw, design.speed.method, speed); - const yaw = await fixDesignAngle(design.angle.yaw, farmSettings.direction); + const laneTime = Math.round((480 / (20 / design.laneDepth)) * 10) / 10; + const laneTimeMinutes = Math.floor(laneTime / 60); + const laneTimeSeconds = laneTime % 60; + const FarmDesignInfoComponent = new EliteContainer(settings) .addTitle(`# ${design.name}`) .addDescription( `**Yaw**: ${yaw}, **Pitch**: ${design.angle.pitch}\n**Speed**: ${speed ?? '1.21 speed has not yet been determined'}${design.speed.depthStrider ? `\n**Depth Strider level**: ${design.speed.depthStrider}` : ''}`, ) .addSeparator() - .addDescription(`**bps**: ${design.bps}${blocksPerSecond ? `\n**Lane time**: ${480 / blocksPerSecond}` : ''}`); + .addDescription( + `**bps**: ${design.bps}\n**Lane Time**: ${laneTimeMinutes !== 0 ? `${laneTimeMinutes}m ${laneTimeSeconds}s` : laneTimeSeconds + 's'}`, + ); if (replacedBy) { FarmDesignInfoComponent.addSeparator().addDescription(`**Design is outdated, use one of these**:\n${replacedBy}`); @@ -266,21 +270,6 @@ async function getFarmInfoComponents( return components; } -async function calcBlocksPerSecond(yaw: number, method: FarmingMethod, speed?: number): Promise { - if (!speed) return undefined; - if (method === 'running into wall' && yaw === 0) { - speed *= 1.02042464775; - yaw = 45; - } - - const angleOffset = Math.abs(yaw) % 90; - - const effectiveSpeed = angleOffset === 0 ? speed : speed * Math.cos((angleOffset * Math.PI) / 180); - - // https://minecraft.fandom.com/wiki/Walking - return (effectiveSpeed * 4.3171) / 100; -} - async function fixDesignAngle(designYaw: number, direction: Direction): Promise { const yaw = designYaw + directionYawOffset('South', direction); From 49bbd8813019f1e4818ad9b143049dbc67c7f5d2 Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Sat, 21 Jun 2025 18:40:59 -0700 Subject: [PATCH 57/61] add bullet points for notes --- src/commands/farm/info.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index d2c33c7..48f40e3 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -160,6 +160,12 @@ async function getFarmInfoComponents( }) .join('\n'); + const notes = design.notes + ?.map((n) => { + return '- ' + n; + }) + .join('\n'); + const speed = design.speed.soulSand ? design.speed[farmSettings.version] : design.speed['1.8.9']; const yaw = await fixDesignAngle(design.angle.yaw, farmSettings.direction); @@ -186,8 +192,8 @@ async function getFarmInfoComponents( FarmDesignInfoComponent.addSeparator().addDescription(resources); } - if (design.notes) { - FarmDesignInfoComponent.addSeparator().addDescription(design.notes.join('\n')); + if (notes) { + FarmDesignInfoComponent.addSeparator().addDescription(notes); } if (design.authors) { From c8ce5b9c7df76c9955b4eea9ad94d1d6b946635a Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Sat, 21 Jun 2025 19:19:23 -0700 Subject: [PATCH 58/61] remove footer on settings component --- src/commands/farm/info.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index 48f40e3..c1ef7ec 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -258,8 +258,7 @@ async function getFarmInfoComponents( .setDefault(farmSettings.version == '1.21'), ), ), - ) - .addFooter(); + ); components.push(settingsComponent); } From 5c5c85e2ab1ee06811933ed6dbf87d736ff0d59b Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Sat, 21 Jun 2025 19:25:10 -0700 Subject: [PATCH 59/61] update farming-weight --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 01e9a19..166ab84 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "cron": "^3.5.0", "date-fns": "^4.1.0", "discord.js": "^14.20.0", - "farming-weight": "^0.9.4", + "farming-weight": "^0.9.5", "openapi-fetch": "^0.14.0", "redis": "^4.7.1", "utf-8-validate": "^6.0.5", From 6d333c21b495325ac0487e08eb05267d1a354808 Mon Sep 17 00:00:00 2001 From: not a cow <104355555+not-a-cowfr@users.noreply.github.com> Date: Sun, 22 Jun 2025 13:31:10 -0700 Subject: [PATCH 60/61] fix buttons/menu interaction --- src/commands/farm/info.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index c1ef7ec..c6742ff 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -104,8 +104,6 @@ export async function execute( return NotYoursReply(inter); } - await inter.deferReply(); - collector.resetTimer(); if (inter.isStringSelectMenu()) { @@ -122,14 +120,10 @@ export async function execute( const components = await getFarmInfoComponents(design, farmSettings, settings); - await interaction.editReply({ + await inter.update({ components, - allowedMentions: { repliedUser: false }, - flags: [MessageFlags.IsComponentsV2], }); - await inter.deleteReply(); - return; }); } From 63962bc75f8ce4783bda756500fde77c27e83fa8 Mon Sep 17 00:00:00 2001 From: Kaeso <24925519+ptlthg@users.noreply.github.com> Date: Fri, 11 Jul 2025 22:55:54 -0400 Subject: [PATCH 61/61] Improve commands a bit --- biome.json | 2 +- src/classes/components.ts | 38 ++++++++++++++++ src/commands/farm/info.ts | 90 ++++++++++++++++++++++++++++++++++++- src/commands/farm/search.ts | 6 +-- 4 files changed, 131 insertions(+), 5 deletions(-) diff --git a/biome.json b/biome.json index aac81d3..b0f5ee4 100644 --- a/biome.json +++ b/biome.json @@ -1,5 +1,5 @@ { - "$schema": "https://biomejs.dev/schemas/2.0.0/schema.json", + "$schema": "https://biomejs.dev/schemas/2.0.2/schema.json", "vcs": { "enabled": false, "clientKind": "git", "useIgnoreFile": false }, "files": { "ignoreUnknown": false, diff --git a/src/classes/components.ts b/src/classes/components.ts index d8e64df..424239d 100644 --- a/src/classes/components.ts +++ b/src/classes/components.ts @@ -6,6 +6,7 @@ import { ButtonStyle, ContainerBuilder, Interaction, + MediaGalleryItemBuilder, SectionBuilder, SeparatorSpacingSize, TextDisplayBuilder, @@ -66,6 +67,30 @@ export class EliteContainer extends ContainerBuilder { return this; } + addImage(url: string, altText?: string) { + const item = new MediaGalleryItemBuilder().setURL(url); + + if (altText) { + item.setDescription(altText); + } + + this.addMediaGalleryComponents((media) => media.addItems(item)); + return this; + } + + addImages(images: { url: string; altText?: string }[]) { + const items = images.map((image) => { + const item = new MediaGalleryItemBuilder().setURL(image.url); + if (image.altText) { + item.setDescription(image.altText); + } + return item; + }); + + this.addMediaGalleryComponents((media) => media.addItems(...items)); + return this; + } + addFooter(separator = true, backButton = '') { if (separator) { this.addSeparator(); @@ -109,6 +134,19 @@ export class EliteContainer extends ContainerBuilder { return this; } + addImageSection(url: string, ...textComponents: string[]) { + const section = new SectionBuilder().setId(10000 + Math.floor(Math.random() * 90000)); + + if (textComponents.length > 0) { + section.addTextDisplayComponents(...textComponents.map((text) => new TextDisplayBuilder().setContent(text))); + } + + section.setThumbnailAccessory((a) => a.setURL(url)); + + this.addSectionComponents(section); + return this; + } + addCollapsible({ collapsed, expanded, opened, radio, header }: CollapsibleSectionData) { const sectionId = 10000 + Math.floor(Math.random() * 90000); const data = { diff --git a/src/commands/farm/info.ts b/src/commands/farm/info.ts index c6742ff..7faf883 100644 --- a/src/commands/farm/info.ts +++ b/src/commands/farm/info.ts @@ -1,5 +1,7 @@ +import { createCanvas } from '@napi-rs/canvas'; import { ActionRowBuilder, + AttachmentBuilder, AutocompleteInteraction, ButtonBuilder, ButtonStyle, @@ -89,10 +91,14 @@ export async function execute( const components = await getFarmInfoComponents(design, farmSettings, settings); + const yaw = await fixDesignAngle(design.angle.yaw, farmSettings.direction); + const image = pitchAndYawImage({ pitch: design.angle.pitch, yaw }, farmSettings.direction); + const reply = await interaction.editReply({ components, allowedMentions: { repliedUser: false }, flags: [MessageFlags.IsComponentsV2], + files: [image], }); const collector = reply.createMessageComponentCollector({ @@ -122,6 +128,12 @@ export async function execute( await inter.update({ components, + files: [ + pitchAndYawImage( + { pitch: design.angle.pitch, yaw: await fixDesignAngle(design.angle.yaw, farmSettings.direction) }, + farmSettings.direction, + ), + ], }); return; @@ -174,6 +186,12 @@ async function getFarmInfoComponents( `**Yaw**: ${yaw}, **Pitch**: ${design.angle.pitch}\n**Speed**: ${speed ?? '1.21 speed has not yet been determined'}${design.speed.depthStrider ? `\n**Depth Strider level**: ${design.speed.depthStrider}` : ''}`, ) .addSeparator() + .addText(`**Max BPS**: \`${design.bps}\``) + .addImage( + 'attachment://yaw-pitch.webp', + `Farm with [Yaw: ${yaw}, Pitch: ${design.angle.pitch}] while facing ${farmSettings.direction}`, + ) + .addSeparator() .addDescription( `**bps**: ${design.bps}\n**Lane Time**: ${laneTimeMinutes !== 0 ? `${laneTimeMinutes}m ${laneTimeSeconds}s` : laneTimeSeconds + 's'}`, ); @@ -183,7 +201,13 @@ async function getFarmInfoComponents( } if (resources) { - FarmDesignInfoComponent.addSeparator().addDescription(resources); + const youtube = design.resources?.find((r) => r.type === ResourceType.Video)?.source; + if (youtube) { + const id = youtube.split('/').pop(); + FarmDesignInfoComponent.addImageSection(`https://img.youtube.com/vi/${id}/mqdefault.jpg`, resources); + } else { + FarmDesignInfoComponent.addSeparator().addDescription(resources); + } } if (notes) { @@ -289,3 +313,67 @@ function directionYawOffset(from: Direction, to: Direction): number { function normalizeAngle(angle: number) { return ((angle + 180) % 360) - 180; } + +function pitchAndYawImage(angle: { pitch: number; yaw: number }, direction: Direction = 'South') { + const bgWidth = 1200; + const bgHeight = 100; + + const canvas = createCanvas(bgWidth, bgHeight); + const ctx = canvas.getContext('2d'); + + ctx.fillStyle = '#84baff'; + ctx.rect(0, 0, bgWidth, bgHeight); + ctx.fill(); + + ctx.fillStyle = '#ffffff'; + ctx.font = '65px "Open Sans"'; + ctx.fillText(`F3 Angle: (${angle.yaw.toFixed(1)} / ${angle.pitch.toFixed(1)})`, 10, 72); + + // Draw a basic compass shape in the right middle + ctx.fillStyle = '#bfbfbf'; + ctx.beginPath(); + ctx.arc(bgWidth - 60, bgHeight / 2, bgHeight / 2 - 10, 0, Math.PI * 2); + ctx.fill(); + ctx.lineWidth = 4; + ctx.strokeStyle = '#ffffff'; + ctx.stroke(); + + // 2. A rounded red line from the center of the circle to the top + ctx.strokeStyle = '#a20508'; + ctx.beginPath(); + switch (direction) { + case 'North': + ctx.moveTo(bgWidth - 60, bgHeight / 2); + ctx.lineTo(bgWidth - 60, bgHeight / 2 - 25); + break; + case 'East': + ctx.moveTo(bgWidth - 60, bgHeight / 2); + ctx.lineTo(bgWidth - 60 + 25, bgHeight / 2); + break; + case 'South': + ctx.moveTo(bgWidth - 60, bgHeight / 2); + ctx.lineTo(bgWidth - 60, bgHeight / 2 + 25); + break; + case 'West': + ctx.moveTo(bgWidth - 60, bgHeight / 2); + ctx.lineTo(bgWidth - 60 - 25, bgHeight / 2); + break; + } + ctx.lineWidth = 4; + ctx.lineCap = 'round'; + ctx.stroke(); + + ctx.fillStyle = '#FFFFFF'; + ctx.font = '14px "Open Sans"'; + + ctx.fillText('N', bgWidth - 64, bgHeight / 2 - 25); + ctx.fillText('E', bgWidth - 64 + 30, bgHeight / 2 + 4); + ctx.fillText('S', bgWidth - 64, bgHeight / 2 + 35); + ctx.fillText('W', bgWidth - 64 - 30, bgHeight / 2 + 4); + + const attachment = new AttachmentBuilder(canvas.toBuffer('image/webp'), { + name: `yaw-pitch.webp`, + }); + + return attachment; +} diff --git a/src/commands/farm/search.ts b/src/commands/farm/search.ts index 0c2d29b..4cfa996 100644 --- a/src/commands/farm/search.ts +++ b/src/commands/farm/search.ts @@ -41,11 +41,11 @@ async function execute(interaction: ChatInputCommandInteraction, settings?: User } component - .addDescription(`### ${data.name}`) + .addText(`### ${data.name}`) .addSectionComponents( new SectionBuilder() - .addTextDisplayComponents((t) => t.setContent(`bps: ${data.bps}`)) - .setButtonAccessory(new ButtonBuilder().setStyle(ButtonStyle.Secondary).setLabel(data.name).setCustomId(id)), + .addTextDisplayComponents((t) => t.setContent(`Max BPS: \`${data.bps}\``)) + .setButtonAccessory(new ButtonBuilder().setStyle(ButtonStyle.Secondary).setLabel('View').setCustomId(id)), ); });