From e95c0827862f5e79e2b8ebcfba3a2f0566a09b5f Mon Sep 17 00:00:00 2001 From: MaxRobinsonTheGreat Date: Wed, 25 Sep 2024 00:15:55 -0500 Subject: [PATCH 1/6] unstuck mode, patch pathfinder --- patches/mineflayer-collectblock+1.4.1.patch | 11 +++++- patches/mineflayer-pathfinder+2.4.5.patch | 4 +- src/agent/coder.js | 10 +++-- src/agent/modes.js | 42 +++++++++++++++++---- 4 files changed, 54 insertions(+), 13 deletions(-) diff --git a/patches/mineflayer-collectblock+1.4.1.patch b/patches/mineflayer-collectblock+1.4.1.patch index cc04fa2..22440f4 100644 --- a/patches/mineflayer-collectblock+1.4.1.patch +++ b/patches/mineflayer-collectblock+1.4.1.patch @@ -1,5 +1,5 @@ diff --git a/node_modules/mineflayer-collectblock/lib/CollectBlock.js b/node_modules/mineflayer-collectblock/lib/CollectBlock.js -index 2c11e8c..bc47dc7 100644 +index 2c11e8c..4697873 100644 --- a/node_modules/mineflayer-collectblock/lib/CollectBlock.js +++ b/node_modules/mineflayer-collectblock/lib/CollectBlock.js @@ -77,7 +77,7 @@ function mineBlock(bot, block, options) { @@ -11,3 +11,12 @@ index 2c11e8c..bc47dc7 100644 options.targets.removeTarget(block); return; } +@@ -195,6 +195,8 @@ class CollectBlock { + throw (0, Util_1.error)('UnresolvedDependency', 'The mineflayer-collectblock plugin relies on the mineflayer-tool plugin to run!'); + } + if (this.movements != null) { ++ this.movements.dontMineUnderFallingBlock = false; ++ this.movements.dontCreateFlow = false; + this.bot.pathfinder.setMovements(this.movements); + } + if (!optionsFull.append) diff --git a/patches/mineflayer-pathfinder+2.4.5.patch b/patches/mineflayer-pathfinder+2.4.5.patch index 6d6f5ad..4c8dc93 100644 --- a/patches/mineflayer-pathfinder+2.4.5.patch +++ b/patches/mineflayer-pathfinder+2.4.5.patch @@ -1,5 +1,5 @@ diff --git a/node_modules/mineflayer-pathfinder/index.js b/node_modules/mineflayer-pathfinder/index.js -index b38bd30..ae3754f 100644 +index b38bd30..cfaa677 100644 --- a/node_modules/mineflayer-pathfinder/index.js +++ b/node_modules/mineflayer-pathfinder/index.js @@ -541,7 +541,7 @@ function inject (bot) { @@ -7,7 +7,7 @@ index b38bd30..ae3754f 100644 if (placingBlock.jump) { bot.setControlState('jump', true) - canPlace = placingBlock.y + 1 < bot.entity.position.y -+ canPlace = placingBlock.y + 1.9 < bot.entity.position.y ++ canPlace = placingBlock.y + 1.8 < bot.entity.position.y } if (canPlace) { if (!lockEquipItem.tryAcquire()) return diff --git a/src/agent/coder.js b/src/agent/coder.js index 67f3081..ee21fd7 100644 --- a/src/agent/coder.js +++ b/src/agent/coder.js @@ -10,6 +10,8 @@ export class Coder { this.generating = false; this.code_template = ''; this.timedout = false; + this.interruptible = true; + this.cur_action_name = ''; readFile('./bots/template.js', 'utf8', (err, data) => { if (err) throw err; @@ -156,10 +158,9 @@ export class Coder { return {success: false, message: null, interrupted: false, timedout: true}; } - async executeResume(func=null, name=null, timeout=10) { + async executeResume(func=null, timeout=10) { if (func != null) { this.resume_func = func; - this.resume_name = name; } if (this.resume_func != null && this.agent.isIdle() && !this.agent.self_prompter.on) { console.log('resuming code...') @@ -174,7 +175,10 @@ export class Coder { cancelResume() { this.resume_func = null; - this.resume_name = null; + } + + setCurActionName(name) { + this.cur_action_name = name.replace(/!/g, ''); } // returns {success: bool, message: string, interrupted: bool, timedout: false} diff --git a/src/agent/modes.js b/src/agent/modes.js index 952fcf0..1abad43 100644 --- a/src/agent/modes.js +++ b/src/agent/modes.js @@ -22,7 +22,7 @@ function say(agent, message) { const modes = [ { name: 'self_preservation', - description: 'Respond to drowning, burning, and damage at low health. Interrupts other actions.', + description: 'Respond to drowning, burning, and damage at low health. Interrupts all actions.', interrupts: ['all'], on: true, active: false, @@ -70,9 +70,38 @@ const modes = [ } } }, + { + name: 'unstuck', + description: 'Attempt to get unstuck when in the same place for a while. Interrupts some actions.', + interrupts: ['collectBlocks', 'goToPlayer', 'collectAllBlocks'], + on: true, + active: false, + prev_location: null, + stuck_time: 0, + last_time: Date.now(), + max_stuck_time: 10, + update: async function (agent) { + if (agent.isIdle()) return; + const bot = agent.bot; + if (this.prev_location && this.prev_location.distanceTo(bot.entity.position) < 1) { + this.stuck_time += (Date.now() - this.last_time) / 1000; + } + else { + this.prev_location = bot.entity.position.clone(); + this.stuck_time = 0; + } + if (this.stuck_time > this.max_stuck_time) { + say(agent, 'I\'m stuck!'); + execute(this, agent, async () => { + await skills.moveAway(bot, 5); + }); + } + this.last_time = Date.now(); + } + }, { name: 'cowardice', - description: 'Run away from enemies. Interrupts other actions.', + description: 'Run away from enemies. Interrupts all actions.', interrupts: ['all'], on: true, active: false, @@ -88,7 +117,7 @@ const modes = [ }, { name: 'self_defense', - description: 'Attack nearby enemies. Interrupts other actions.', + description: 'Attack nearby enemies. Interrupts all actions.', interrupts: ['all'], on: true, active: false, @@ -105,7 +134,7 @@ const modes = [ { name: 'hunting', description: 'Hunt nearby animals when idle.', - interrupts: ['defaults'], + interrupts: [], on: true, active: false, update: async function (agent) { @@ -281,9 +310,8 @@ class ModeController { this.unPauseAll(); } for (let mode of this.modes_list) { - let available = mode.interrupts.includes('all') || this.agent.isIdle(); - let interruptible = this.agent.coder.interruptible && (mode.interrupts.includes('defaults') || mode.interrupts.includes(this.agent.coder.resume_name)); - if (mode.on && !mode.paused && !mode.active && (available || interruptible)) { + let interruptible = this.agent.coder.interruptible && (mode.interrupts.includes('all') || mode.interrupts.some(i => i === this.agent.coder.cur_action_name)); + if (mode.on && !mode.paused && !mode.active && (this.agent.isIdle() || interruptible)) { await mode.update(this.agent); } if (mode.active) break; From d44c99356faeb9996660ed687af8682fddd90642 Mon Sep 17 00:00:00 2001 From: MaxRobinsonTheGreat Date: Thu, 26 Sep 2024 22:28:46 -0500 Subject: [PATCH 2/6] reworked mode interrupts, added equip and discard --- src/agent/coder.js | 10 ++++---- src/agent/commands/actions.js | 43 ++++++++++++++++++++++++++--------- src/agent/commands/index.js | 11 +++++++-- src/agent/library/skills.js | 24 ++++++++++++++----- src/agent/modes.js | 12 ++++++---- 5 files changed, 71 insertions(+), 29 deletions(-) diff --git a/src/agent/coder.js b/src/agent/coder.js index ee21fd7..7067348 100644 --- a/src/agent/coder.js +++ b/src/agent/coder.js @@ -10,7 +10,6 @@ export class Coder { this.generating = false; this.code_template = ''; this.timedout = false; - this.interruptible = true; this.cur_action_name = ''; readFile('./bots/template.js', 'utf8', (err, data) => { @@ -159,14 +158,14 @@ export class Coder { } async executeResume(func=null, timeout=10) { - if (func != null) { + if (func != null) { // start new resume this.resume_func = func; + this.resume_name = this.cur_action_name; } if (this.resume_func != null && this.agent.isIdle() && !this.agent.self_prompter.on) { - console.log('resuming code...') - this.interruptible = true; + this.cur_action_name = this.resume_name; let res = await this.execute(this.resume_func, timeout); - this.interruptible = false; + this.cur_action_name = ''; return res; } else { return {success: false, message: null, interrupted: false, timedout: false}; @@ -175,6 +174,7 @@ export class Coder { cancelResume() { this.resume_func = null; + this.resume_name = null; } setCurActionName(name) { diff --git a/src/agent/commands/actions.js b/src/agent/commands/actions.js index 651f362..26dc0e5 100644 --- a/src/agent/commands/actions.js +++ b/src/agent/commands/actions.js @@ -1,17 +1,16 @@ import * as skills from '../library/skills.js'; import settings from '../../../settings.js'; -function wrapExecution(func, timeout=-1, resume_name=null) { +function wrapExecution(func, resume=false, timeout=-1) { return async function (agent, ...args) { let code_return; - if (resume_name != null) { - code_return = await agent.coder.executeResume(async () => { - await func(agent, ...args); - }, resume_name, timeout); + const wrappedFunction = async () => { + await func(agent, ...args); + }; + if (resume) { + code_return = await agent.coder.executeResume(wrappedFunction, timeout); } else { - code_return = await agent.coder.execute(async () => { - await func(agent, ...args); - }, timeout); + code_return = await agent.coder.execute(wrappedFunction, timeout); } if (code_return.interrupted && !code_return.timedout) return; @@ -88,7 +87,7 @@ export const actionsList = [ }, perform: wrapExecution(async (agent, player_name, follow_dist) => { await skills.followPlayer(agent.bot, player_name, follow_dist); - }, -1, 'followPlayer') + }, true) }, { name: '!goToBlock', @@ -145,6 +144,28 @@ export const actionsList = [ await skills.giveToPlayer(agent.bot, item_name, player_name, num); }) }, + { + name: '!equip', + description: 'Equip the given item.', + params: {'item_name': '(string) The name of the item to equip.'}, + perform: wrapExecution(async (agent, item_name) => { + await skills.equip(agent.bot, item_name); + }) + }, + { + name: '!discard', + description: 'Discard the given item from the inventory.', + params: { + 'item_name': '(string) The name of the item to discard.', + 'num': '(number) The number of items to discard.', + }, + perform: wrapExecution(async (agent, item_name, num) => { + const start_loc = agent.bot.entity.position; + await skills.moveAway(agent.bot, 5); + await skills.discard(agent.bot, item_name, num); + await skills.goToPosition(agent.bot, start_loc.x, start_loc.y, start_loc.z, 0); + }) + }, { name: '!collectBlocks', description: 'Collect the nearest blocks of a given type.', @@ -154,7 +175,7 @@ export const actionsList = [ }, perform: wrapExecution(async (agent, type, num) => { await skills.collectBlock(agent.bot, type, num); - }, 10) // 10 minute timeout + }, false, 10) // 10 minute timeout }, { name: '!collectAllBlocks', @@ -166,7 +187,7 @@ export const actionsList = [ let success = await skills.collectBlock(agent.bot, type, 1); if (!success) agent.coder.cancelResume(); - }, 10, 'collectAllBlocks') // 10 minute timeout + }, true, 3) // 3 minute timeout }, { name: '!craftRecipe', diff --git a/src/agent/commands/index.js b/src/agent/commands/index.js index 4e3d191..64252d4 100644 --- a/src/agent/commands/index.js +++ b/src/agent/commands/index.js @@ -82,6 +82,7 @@ export async function executeCommand(agent, message) { let parsed = parseCommandMessage(message); if (parsed) { const command = getCommand(parsed.commandName); + const is_action = isAction(command.name); let numArgs = 0; if (parsed.args) { numArgs = parsed.args.length; @@ -89,8 +90,14 @@ export async function executeCommand(agent, message) { console.log('parsed command:', parsed); if (numArgs !== numParams(command)) return `Command ${command.name} was given ${numArgs} args, but requires ${numParams(command)} args.`; - else - return await command.perform(agent, ...parsed.args); + else { + if (is_action) + agent.coder.setCurActionName(command.name); + const result = await command.perform(agent, ...parsed.args); + if (is_action) + agent.coder.setCurActionName(command.name); + return result; + } } else return `Command is incorrectly formatted`; diff --git a/src/agent/library/skills.js b/src/agent/library/skills.js index ec887a2..77c6c87 100644 --- a/src/agent/library/skills.js +++ b/src/agent/library/skills.js @@ -648,23 +648,35 @@ export async function placeBlock(bot, blockType, x, y, z, placeOn='bottom', dont } } -export async function equip(bot, itemName, bodyPart) { +export async function equip(bot, itemName) { /** - * Equip the given item to the given body part, like tools or armor. + * Equip the given item to the proper body part, like tools or armor. * @param {MinecraftBot} bot, reference to the minecraft bot. * @param {string} itemName, the item or block name to equip. - * @param {string} bodyPart, the body part to equip the item to. * @returns {Promise} true if the item was equipped, false otherwise. * @example - * await skills.equip(bot, "iron_pickaxe", "hand"); - * await skills.equip(bot, "diamond_chestplate", "torso"); + * await skills.equip(bot, "iron_pickaxe"); **/ let item = bot.inventory.items().find(item => item.name === itemName); if (!item) { log(bot, `You do not have any ${itemName} to equip.`); return false; } - await bot.equip(item, bodyPart); + if (itemName.includes('leggings')) { + await bot.equip(item, 'legs'); + } + else if (itemName.includes('boots')) { + await bot.equip(item, 'feet'); + } + else if (itemName.includes('helmet')) { + await bot.equip(item, 'head'); + } + else if (itemName.includes('chestplate')) { + await bot.equip(item, 'torso'); + } + else { + await bot.equip(item, 'hand'); + } return true; } diff --git a/src/agent/modes.js b/src/agent/modes.js index 1abad43..35c0c79 100644 --- a/src/agent/modes.js +++ b/src/agent/modes.js @@ -73,17 +73,18 @@ const modes = [ { name: 'unstuck', description: 'Attempt to get unstuck when in the same place for a while. Interrupts some actions.', - interrupts: ['collectBlocks', 'goToPlayer', 'collectAllBlocks'], + interrupts: ['collectBlocks', 'goToPlayer', 'collectAllBlocks', 'goToPlace'], on: true, active: false, prev_location: null, + distance: 2, stuck_time: 0, last_time: Date.now(), - max_stuck_time: 10, + max_stuck_time: 20, update: async function (agent) { if (agent.isIdle()) return; const bot = agent.bot; - if (this.prev_location && this.prev_location.distanceTo(bot.entity.position) < 1) { + if (this.prev_location && this.prev_location.distanceTo(bot.entity.position) < this.distance) { this.stuck_time += (Date.now() - this.last_time) / 1000; } else { @@ -159,7 +160,8 @@ const modes = [ noticed_at: -1, update: async function (agent) { let item = world.getNearestEntityWhere(agent.bot, entity => entity.name === 'item', 8); - if (item && item !== this.prev_item && await world.isClearPath(agent.bot, item)) { + let empty_inv_slots = agent.bot.inventory.emptySlotCount(); + if (item && item !== this.prev_item && await world.isClearPath(agent.bot, item) && empty_inv_slots > 1) { if (this.noticed_at === -1) { this.noticed_at = Date.now(); } @@ -310,7 +312,7 @@ class ModeController { this.unPauseAll(); } for (let mode of this.modes_list) { - let interruptible = this.agent.coder.interruptible && (mode.interrupts.includes('all') || mode.interrupts.some(i => i === this.agent.coder.cur_action_name)); + let interruptible = mode.interrupts.some(i => i === 'all') || mode.interrupts.some(i => i === this.agent.coder.cur_action_name); if (mode.on && !mode.paused && !mode.active && (this.agent.isIdle() || interruptible)) { await mode.update(this.agent); } From de7883a0d237cbab4fe84f71f659232d13bdce4a Mon Sep 17 00:00:00 2001 From: MaxRobinsonTheGreat Date: Fri, 27 Sep 2024 17:03:00 -0500 Subject: [PATCH 3/6] chest commands, behavior log, better stability --- src/agent/agent.js | 14 ++++++ src/agent/commands/actions.js | 30 +++++++++++ src/agent/library/skills.js | 95 +++++++++++++++++++++++++++++++++++ src/agent/modes.js | 8 +++ 4 files changed, 147 insertions(+) diff --git a/src/agent/agent.js b/src/agent/agent.js index 801e243..ef21f34 100644 --- a/src/agent/agent.js +++ b/src/agent/agent.js @@ -128,6 +128,16 @@ export class Agent { const checkInterrupt = () => this.self_prompter.shouldInterrupt(self_prompt) || this.shut_up; + let behavior_log = this.bot.modes.flushBehaviorLog(); + if (behavior_log !== '') { + const MAX_LOG = 500; + if (behavior_log.length > MAX_LOG) { + behavior_log = behavior_log.substring(behavior_log.length - MAX_LOG) + '...'; + } + behavior_log = 'Recent behaviors log: \n' + behavior_log.substring(behavior_log.indexOf('\n')); + await this.history.add('system', behavior_log); + } + await this.history.add(source, message); this.history.save(); @@ -239,6 +249,10 @@ export class Agent { this.bot.on('idle', () => { this.bot.clearControlStates(); this.bot.pathfinder.stop(); // clear any lingering pathfinder + if (this.bot.currentWindow) { + this.bot.chat('Closing window...'); + this.bot.closeWindow(this.bot.currentWindow); + } this.bot.modes.unPauseAll(); this.coder.executeResume(); }); diff --git a/src/agent/commands/actions.js b/src/agent/commands/actions.js index 26dc0e5..efd9609 100644 --- a/src/agent/commands/actions.js +++ b/src/agent/commands/actions.js @@ -152,6 +152,36 @@ export const actionsList = [ await skills.equip(agent.bot, item_name); }) }, + { + name: '!putInChest', + description: 'Put the given item in the nearest chest.', + params: { + 'item_name': '(string) The name of the item to put in the chest.', + 'num': '(number) The number of items to put in the chest.' + }, + perform: wrapExecution(async (agent, item_name, num) => { + await skills.putInChest(agent.bot, item_name, num); + }) + }, + { + name: '!takeFromChest', + description: 'Take the given items from the nearest chest.', + params: { + 'item_name': '(string) The name of the item to take.', + 'num': '(number) The number of items to take.' + }, + perform: wrapExecution(async (agent, item_name, num) => { + await skills.takeFromChest(agent.bot, item_name, num); + }) + }, + { + name: '!viewChest', + description: 'View the items/counts of the nearest chest.', + params: { }, + perform: wrapExecution(async (agent) => { + await skills.viewChest(agent.bot); + }) + }, { name: '!discard', description: 'Discard the given item from the inventory.', diff --git a/src/agent/library/skills.js b/src/agent/library/skills.js index 77c6c87..7ef87b2 100644 --- a/src/agent/library/skills.js +++ b/src/agent/library/skills.js @@ -201,6 +201,7 @@ export async function smeltItem(bot, itemName, num=1) { break; } } + await bot.closeWindow(furnace); if (placedFurnace) { await collectBlock(bot, 'furnace', 1); @@ -382,6 +383,12 @@ export async function collectBlock(bot, blockType, num=1, exclude=null) { ); } } + const movements = new pf.Movements(bot); + movements.dontMineUnderFallingBlock = false; + blocks = blocks.filter( + block => movements.safeToBreak(block) + ); + if (blocks.length === 0) { if (collected === 0) log(bot, `No ${blockType} nearby to collect.`); @@ -711,6 +718,94 @@ export async function discard(bot, itemName, num=-1) { return true; } +export async function putInChest(bot, itemName, num=-1) { + /** + * Put the given item in the nearest chest. + * @param {MinecraftBot} bot, reference to the minecraft bot. + * @param {string} itemName, the item or block name to put in the chest. + * @param {number} num, the number of items to put in the chest. Defaults to -1, which puts all items. + * @returns {Promise} true if the item was put in the chest, false otherwise. + * @example + * await skills.putInChest(bot, "oak_log"); + **/ + let chest = world.getNearestBlock(bot, 'chest', 32); + if (!chest) { + log(bot, `Could not find a chest nearby.`); + return false; + } + let item = bot.inventory.items().find(item => item.name === itemName); + if (!item) { + log(bot, `You do not have any ${itemName} to put in the chest.`); + return false; + } + let to_put = num === -1 ? item.count : Math.min(num, item.count); + await goToPosition(bot, chest.position.x, chest.position.y, chest.position.z, 2); + const chestContainer = await bot.openContainer(chest); + await chestContainer.deposit(item.type, null, to_put); + await chestContainer.close(); + log(bot, `Successfully put ${to_put} ${itemName} in the chest.`); + return true; +} + +export async function takeFromChest(bot, itemName, num=-1) { + /** + * Take the given item from the nearest chest. + * @param {MinecraftBot} bot, reference to the minecraft bot. + * @param {string} itemName, the item or block name to take from the chest. + * @param {number} num, the number of items to take from the chest. Defaults to -1, which takes all items. + * @returns {Promise} true if the item was taken from the chest, false otherwise. + * @example + * await skills.takeFromChest(bot, "oak_log"); + * **/ + let chest = world.getNearestBlock(bot, 'chest', 32); + if (!chest) { + log(bot, `Could not find a chest nearby.`); + return false; + } + await goToPosition(bot, chest.position.x, chest.position.y, chest.position.z, 2); + const chestContainer = await bot.openContainer(chest); + let item = chestContainer.containerItems().find(item => item.name === itemName); + if (!item) { + log(bot, `Could not find any ${itemName} in the chest.`); + await chestContainer.close(); + return false; + } + let to_take = num === -1 ? item.count : Math.min(num, item.count); + await chestContainer.withdraw(item.type, null, to_take); + await chestContainer.close(); + log(bot, `Successfully took ${to_take} ${itemName} from the chest.`); + return true; +} + +export async function viewChest(bot) { + /** + * View the contents of the nearest chest. + * @param {MinecraftBot} bot, reference to the minecraft bot. + * @returns {Promise} true if the chest was viewed, false otherwise. + * @example + * await skills.viewChest(bot); + * **/ + let chest = world.getNearestBlock(bot, 'chest', 32); + if (!chest) { + log(bot, `Could not find a chest nearby.`); + return false; + } + await goToPosition(bot, chest.position.x, chest.position.y, chest.position.z, 2); + const chestContainer = await bot.openContainer(chest); + let items = chestContainer.containerItems(); + if (items.length === 0) { + log(bot, `The chest is empty.`); + } + else { + log(bot, `The chest contains:`); + for (let item of items) { + log(bot, `${item.count} ${item.name}`); + } + } + await chestContainer.close(); + return true; +} + export async function eat(bot, foodName="") { /** * Eat the given item. If no item is given, it will eat the first food item in the bot's inventory. diff --git a/src/agent/modes.js b/src/agent/modes.js index 35c0c79..653598f 100644 --- a/src/agent/modes.js +++ b/src/agent/modes.js @@ -4,6 +4,7 @@ import * as mc from '../utils/mcdata.js'; import settings from '../../settings.js' function say(agent, message) { + agent.bot.modes.behavior_log += message + '\n'; if (agent.shut_up || !settings.narrate_behavior) return; agent.bot.chat(message); } @@ -261,6 +262,7 @@ class ModeController { this.agent = agent; this.modes_list = modes; this.modes_map = {}; + this.behavior_log = ''; for (let mode of this.modes_list) { this.modes_map[mode.name] = mode; } @@ -320,6 +322,12 @@ class ModeController { } } + flushBehaviorLog() { + const log = this.behavior_log; + this.behavior_log = ''; + return log; + } + getJson() { let res = {}; for (let mode of this.modes_list) { From f3d2f29652fe02245486efef18006d096479d6f1 Mon Sep 17 00:00:00 2001 From: MaxRobinsonTheGreat Date: Fri, 27 Sep 2024 17:13:23 -0500 Subject: [PATCH 4/6] unset action name when done --- src/agent/commands/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/agent/commands/index.js b/src/agent/commands/index.js index 64252d4..199c5e9 100644 --- a/src/agent/commands/index.js +++ b/src/agent/commands/index.js @@ -95,7 +95,7 @@ export async function executeCommand(agent, message) { agent.coder.setCurActionName(command.name); const result = await command.perform(agent, ...parsed.args); if (is_action) - agent.coder.setCurActionName(command.name); + agent.coder.setCurActionName(''); return result; } } From 675594db08e45a60bee2c7f9a75b466e58a46e4a Mon Sep 17 00:00:00 2001 From: Maximus Date: Sun, 29 Sep 2024 12:31:23 -0700 Subject: [PATCH 5/6] removed unused closewindow --- src/agent/agent.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/agent/agent.js b/src/agent/agent.js index ef21f34..c3d7ad9 100644 --- a/src/agent/agent.js +++ b/src/agent/agent.js @@ -249,10 +249,6 @@ export class Agent { this.bot.on('idle', () => { this.bot.clearControlStates(); this.bot.pathfinder.stop(); // clear any lingering pathfinder - if (this.bot.currentWindow) { - this.bot.chat('Closing window...'); - this.bot.closeWindow(this.bot.currentWindow); - } this.bot.modes.unPauseAll(); this.coder.executeResume(); }); From 14098ab5d225a775d84925443f71b726ca3462e5 Mon Sep 17 00:00:00 2001 From: Maximus Date: Sun, 29 Sep 2024 13:35:15 -0700 Subject: [PATCH 6/6] added unstuck to followPlayer --- src/agent/agent.js | 4 ++-- src/agent/library/skills.js | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/agent/agent.js b/src/agent/agent.js index c3d7ad9..547c06b 100644 --- a/src/agent/agent.js +++ b/src/agent/agent.js @@ -129,10 +129,10 @@ export class Agent { const checkInterrupt = () => this.self_prompter.shouldInterrupt(self_prompt) || this.shut_up; let behavior_log = this.bot.modes.flushBehaviorLog(); - if (behavior_log !== '') { + if (behavior_log.trim().length > 0) { const MAX_LOG = 500; if (behavior_log.length > MAX_LOG) { - behavior_log = behavior_log.substring(behavior_log.length - MAX_LOG) + '...'; + behavior_log = '...' + behavior_log.substring(behavior_log.length - MAX_LOG); } behavior_log = 'Recent behaviors log: \n' + behavior_log.substring(behavior_log.indexOf('\n')); await this.history.add('system', behavior_log); diff --git a/src/agent/library/skills.js b/src/agent/library/skills.js index 7ef87b2..0782562 100644 --- a/src/agent/library/skills.js +++ b/src/agent/library/skills.js @@ -964,12 +964,33 @@ export async function followPlayer(bot, username, distance=4) { bot.pathfinder.setGoal(new pf.goals.GoalFollow(player, distance), true); log(bot, `You are now actively following player ${username}.`); + let last_time = Date.now(); + let stuck_time = 0; + let last_pos = bot.entity.position.clone(); while (!bot.interrupt_code) { await new Promise(resolve => setTimeout(resolve, 500)); + const delta = Date.now() - last_time; // in cheat mode, if the distance is too far, teleport to the player if (bot.modes.isOn('cheat') && bot.entity.position.distanceTo(player.position) > 100 && player.isOnGround) { await goToPlayer(bot, username); } + if (bot.modes.isOn('unstuck')) { + const far_away = bot.entity.position.distanceTo(player.position) > distance + 1; + if (far_away && bot.entity.position.distanceTo(last_pos) <= 2) { + stuck_time += delta; + if (stuck_time > 10000) { + log(bot, `Got stuck, attempting to move away.`); + bot.pathfinder.stop(); + await moveAway(bot, 4); + return false; + } + } + else { + stuck_time = 0; + last_pos = bot.entity.position.clone(); + } + } + last_time = Date.now(); } return true; }