From c02bdb69c60fdc4aacea0d9a6b1c9889b9e72b7d Mon Sep 17 00:00:00 2001 From: Vineeth <94882582+FantomWolf182@users.noreply.github.com> Date: Mon, 28 Oct 2024 21:22:31 -0500 Subject: [PATCH 1/2] Update skills.js --- src/agent/library/skills.js | 138 +++++++++++++++++++++++++++++++++--- 1 file changed, 130 insertions(+), 8 deletions(-) diff --git a/src/agent/library/skills.js b/src/agent/library/skills.js index b575ff1..b3c2b36 100644 --- a/src/agent/library/skills.js +++ b/src/agent/library/skills.js @@ -716,9 +716,6 @@ export async function equip(bot, itemName) { else if (itemName.includes('chestplate') || itemName.includes('elytra')) { await bot.equip(item, 'torso'); } - else if (itemName.includes('shield')) { - await bot.equip(item, 'off-hand'); - } else { await bot.equip(item, 'hand'); } @@ -1085,11 +1082,10 @@ export async function avoidEnemies(bot, distance=16) { return true; } -export async function stay(bot, seconds=30) { +export async function stay(bot) { /** * Stay in the current position until interrupted. Disables all modes. * @param {MinecraftBot} bot, reference to the minecraft bot. - * @param {number} seconds, the number of seconds to stay. Defaults to 30. -1 for indefinite. * @returns {Promise} true if the bot stayed, false otherwise. * @example * await skills.stay(bot); @@ -1101,11 +1097,9 @@ export async function stay(bot, seconds=30) { bot.modes.pause('hunting'); bot.modes.pause('torch_placing'); bot.modes.pause('item_collecting'); - let start = Date.now(); - while (!bot.interrupt_code && (seconds === -1 || Date.now() - start < seconds*1000)) { + while (!bot.interrupt_code) { await new Promise(resolve => setTimeout(resolve, 500)); } - log(bot, `Stayed for ${(Date.now() - start)/1000} seconds.`); return true; } @@ -1269,3 +1263,131 @@ export async function activateNearestBlock(bot, type) { log(bot, `Activated ${type} at x:${block.position.x.toFixed(1)}, y:${block.position.y.toFixed(1)}, z:${block.position.z.toFixed(1)}.`); return true; } + +export async function showVillagers (bot) { + const villagers = Object.keys(bot.entities).map(id => bot.entities[id]).filter(e => e.entityType === bot.registry.entitiesByName.villager.id) + const closeVillagersId = villagers.filter(e => bot.entity.position.distanceTo(e.position) < 3).map(e => e.id) + bot.chat(`found ${villagers.length} villagers`) + bot.chat(`villager(s) you can trade with: ${closeVillagersId.join(', ')}`) + console.log(`villager(s) you can trade with: ${closeVillagersId.join(', ')}`) +} + +export async function showTrades (bot, id) { + const e = bot.entities[id] + switch (true) { + case !e: + bot.chat(`cant find entity with id ${id}`) + break + case e.entityType !== bot.registry.entitiesByName.villager.id: + bot.chat('entity is not a villager') + break + case bot.entity.position.distanceTo(e.position) > 3: + bot.chat('villager out of reach') + break + default: { + const villager = await bot.openVillager(e) + villager.close() + stringifyTrades(bot, villager.trades).forEach((trade, i) => { + console.log(`${i + 1}: ${trade}`) + bot.chat(`${i + 1}: ${trade}`) + }) + } + } +} + +export async function trade (bot, id, index, count) { + const e = bot.entities[id] + switch (true) { + case !e: + bot.chat(`cant find entity with id ${id}`) + break + case e.entityType !== bot.registry.entitiesByName.villager.id: + bot.chat('entity is not a villager') + break + case bot.entity.position.distanceTo(e.position) > 3: + bot.chat('villager out of reach') + break + default: { + const villager = await bot.openVillager(e) + const trade = villager.trades[index - 1] + count = count || trade.maximumNbTradeUses - trade.nbTradeUses + switch (true) { + case !trade: + villager.close() + bot.chat('trade not found') + break + case trade.disabled: + villager.close() + bot.chat('trade is disabled') + break + case trade.maximumNbTradeUses - trade.nbTradeUses < count: + villager.close() + bot.chat('cant trade that often') + break + case !hasResources(villager.slots, trade, count): + villager.close() + bot.chat('dont have the resources to do that trade') + break + default: + bot.chat('starting to trade') + try { + await bot.trade(villager, index - 1, count) + bot.chat(`traded ${count} times`) + } catch (err) { + bot.chat('an error occurred while trying to trade') + console.log(err) + } + villager.close() + } + } + } +} + +function hasResources (window, trade, count) { + const first = enough(trade.inputItem1, count) + const second = !trade.inputItem2 || enough(trade.inputItem2, count) + return first && second + + function enough (item, count) { + let c = 0 + window.forEach((element) => { + if (element && element.type === item.type && element.metadata === item.metadata) { + c += element.count + } + }) + return c >= item.count * count + } + } + +function stringifyTrades (bot, trades) { + return trades.map((trade) => { + let text = stringifyItem(bot, trade.inputItem1) + if (trade.inputItem2) text += ` & ${stringifyItem(bot, trade.inputItem2)}` + if (trade.disabled) text += ' x '; else text += ' ยป ' + text += stringifyItem(bot, trade.outputItem) + return `(${trade.nbTradeUses}/${trade.maximumNbTradeUses}) ${text}` + }) +} +function stringifyItem (bot, item) { + if (!item) return 'nothing' + let text = `${item.count} ${item.displayName}` + if (item.nbt && item.nbt.value) { + const ench = item.nbt.value.ench + const StoredEnchantments = item.nbt.value.StoredEnchantments + const Potion = item.nbt.value.Potion + const display = item.nbt.value.display + + if (Potion) text += ` of ${Potion.value.replace(/_/g, ' ').split(':')[1] || 'unknown type'}` + if (display) text += ` named ${display.value.Name.value}` + if (ench || StoredEnchantments) { + text += ` enchanted with ${(ench || StoredEnchantments).value.value.map((e) => { + const lvl = e.lvl.value + const id = e.id.value + return bot.registry.enchantments[id].displayName + ' ' + lvl + }).join(' ')}` + } + } + return text +} + + From 5feee007b69478b99db85762da2d31fe3c39f47d Mon Sep 17 00:00:00 2001 From: Vineeth <94882582+FantomWolf182@users.noreply.github.com> Date: Mon, 28 Oct 2024 21:23:19 -0500 Subject: [PATCH 2/2] Update actions.js --- src/agent/commands/actions.js | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/src/agent/commands/actions.js b/src/agent/commands/actions.js index a80ad29..5b9081e 100644 --- a/src/agent/commands/actions.js +++ b/src/agent/commands/actions.js @@ -306,9 +306,8 @@ export const actionsList = [ { name: '!stay', description: 'Stay in the current location no matter what. Pauses all modes.', - params: {'type': { type: 'int', description: 'The number of seconds to stay. -1 for forever.', domain: [-1, Number.MAX_SAFE_INTEGER] }}, - perform: wrapExecution(async (agent, seconds) => { - await skills.stay(agent.bot, seconds); + perform: wrapExecution(async (agent) => { + await skills.stay(agent.bot); }) }, { @@ -338,6 +337,34 @@ export const actionsList = [ agent.self_prompter.start(prompt); // don't await, don't return } }, + { + name: '!showVillagers', + description: 'Show all villagers nearby.', + perform: wrapExecution(async (agent) => { + return await skills.showVillagers(agent.bot); + }) + }, + { + name: '!showTrades', + description: 'Show trades of a specified villager.', + params: {'id': { type: 'string', description: 'The id number of the villager that you want to trade with.' }}, + perform: wrapExecution(async (agent, id) => { + await skills.showTrades(agent.bot, id); + }) + }, + { + name: '!trade', + description: 'trade with a specified villager.', + params: { + 'id': { type: 'string', description: 'The id number of the villager that you want to trade with.' }, + 'index': { type: 'string', description: 'The index of the trade you want executed.' }, + 'count': { type: 'string', description: 'How many times that trade should be executed.' }, + }, + perform: wrapExecution(async (agent, id, index, count) => { + await skills.trade(agent.bot, id, index, count); + }) + }, + { name: '!endGoal', description: 'Call when you have accomplished your goal. It will stop self-prompting and the current action. ',