From 19f8238aa1def5247257e169c796db775dbb2ee2 Mon Sep 17 00:00:00 2001 From: MaxRobinsonTheGreat Date: Sun, 3 Nov 2024 22:17:28 -0600 Subject: [PATCH] renamed file, refactor labeling --- src/agent/{actions.js => action_manager.js} | 24 ++++---- src/agent/agent.js | 4 +- src/agent/commands/actions.js | 62 ++++++++++++--------- src/agent/modes.js | 6 +- 4 files changed, 53 insertions(+), 43 deletions(-) rename src/agent/{actions.js => action_manager.js} (87%) diff --git a/src/agent/actions.js b/src/agent/action_manager.js similarity index 87% rename from src/agent/actions.js rename to src/agent/action_manager.js index ca25aee..833f3c0 100644 --- a/src/agent/actions.js +++ b/src/agent/action_manager.js @@ -15,7 +15,7 @@ export class ActionManager { async runAction(actionLabel, actionFn, { timeout, resume = false } = {}) { if (resume) { - return this._executeResume(actionFn, timeout); + return this._executeResume(actionLabel, actionFn, timeout); } else { return this._executeAction(actionLabel, actionFn, timeout); } @@ -23,28 +23,28 @@ export class ActionManager { async stop() { if (!this.executing) return; - console.trace(); - const start = Date.now(); + const timeout = setTimeout(() => { + this.agent.cleanKill('Code execution refused stop after 10 seconds. Killing process.'); + }, 10000); while (this.executing) { - this.agent.interruptBot(); + this.agent.requestInterrupt(); console.log('waiting for code to finish executing...'); - await new Promise(resolve => setTimeout(resolve, 1000)); - if (Date.now() - start > 10 * 1000) { - this.agent.cleanKill('Code execution refused stop after 10 seconds. Killing process.'); - } + await new Promise(resolve => setTimeout(resolve, 300)); } - } + clearTimeout(timeout); + } cancelResume() { this.resume_func = null; this.resume_name = null; } - async _executeResume(actionFn = null, timeout = 10) { + async _executeResume(actionLabel = null, actionFn = null, timeout = 10) { const new_resume = actionFn != null; if (new_resume) { // start new resume this.resume_func = actionFn; - this.resume_name = this.currentActionLabel; + assert(actionLabel != null, 'actionLabel is required for new resume'); + this.resume_name = actionLabel; } if (this.resume_func != null && this.agent.isIdle() && (!this.agent.self_prompter.on || new_resume)) { this.currentActionLabel = this.resume_name; @@ -64,7 +64,7 @@ export class ActionManager { // await current action to finish (executing=false), with 10 seconds timeout // also tell agent.bot to stop various actions if (this.executing) { - console.log(`new action "${actionLabel}" trying to interrupt current action "${this.currentActionLabel}"`); + console.log(`action "${actionLabel}" trying to interrupt current action "${this.currentActionLabel}"`); } await this.stop(); diff --git a/src/agent/agent.js b/src/agent/agent.js index 99f7f00..d821ecb 100644 --- a/src/agent/agent.js +++ b/src/agent/agent.js @@ -4,7 +4,7 @@ import { Prompter } from './prompter.js'; import { initModes } from './modes.js'; import { initBot } from '../utils/mcdata.js'; import { containsCommand, commandExists, executeCommand, truncCommandMessage, isAction } from './commands/index.js'; -import { ActionManager } from './actions.js'; +import { ActionManager } from './action_manager.js'; import { NPCContoller } from './npc/controller.js'; import { MemoryBank } from './memory_bank.js'; import { SelfPrompter } from './self_prompter.js'; @@ -93,7 +93,7 @@ export class Agent { }); } - interruptBot() { + requestInterrupt() { this.bot.interrupt_code = true; this.bot.collectBlock.cancelTask(); this.bot.pathfinder.stop(); diff --git a/src/agent/commands/actions.js b/src/agent/commands/actions.js index 3a2e453..ab34894 100644 --- a/src/agent/commands/actions.js +++ b/src/agent/commands/actions.js @@ -1,8 +1,16 @@ import * as skills from '../library/skills.js'; import settings from '../../../settings.js'; -function runAsAction (actionLabel, actionFn, resume = false, timeout = -1) { - return async function (agent, ...args) { +function runAsAction (actionFn, resume = false, timeout = -1) { + let actionLabel = null; // Will be set on first use + + const wrappedAction = async function (agent, ...args) { + // Set actionLabel only once, when the action is first created + if (!actionLabel) { + const actionObj = actionsList.find(a => a.perform === wrappedAction); + actionLabel = actionObj.name.substring(1); // Remove the ! prefix + } + const actionFnWithAgent = async () => { await actionFn(agent, ...args); }; @@ -11,6 +19,8 @@ function runAsAction (actionLabel, actionFn, resume = false, timeout = -1) { return; return code_return.message; } + + return wrappedAction; } export const actionsList = [ @@ -73,18 +83,18 @@ export const actionsList = [ 'player_name': {type: 'string', description: 'The name of the player to go to.'}, 'closeness': {type: 'float', description: 'How close to get to the player.', domain: [0, Infinity]} }, - perform: runAsAction('goToPlayer', async (agent, player_name, closeness) => { + perform: runAsAction(async (agent, player_name, closeness) => { return await skills.goToPlayer(agent.bot, player_name, closeness); }) }, { name: '!followPlayer', - description: 'Endlessly follow the given player. Will defend that player if self_defense mode is on.', + description: 'Endlessly follow the given player.', params: { 'player_name': {type: 'string', description: 'name of the player to follow.'}, 'follow_dist': {type: 'float', description: 'The distance to follow from.', domain: [0, Infinity]} }, - perform: runAsAction('followPlayer', async (agent, player_name, follow_dist) => { + perform: runAsAction(async (agent, player_name, follow_dist) => { await skills.followPlayer(agent.bot, player_name, follow_dist); }, true) }, @@ -94,9 +104,9 @@ export const actionsList = [ params: { 'type': { type: 'BlockName', description: 'The block type to go to.' }, 'closeness': { type: 'float', description: 'How close to get to the block.', domain: [0, Infinity] }, - 'search_range': { type: 'float', description: 'The distance to search for the block.', domain: [0, Infinity] } + 'search_range': { type: 'float', description: 'The range to search for the block.', domain: [0, 512] } }, - perform: runAsAction('goToBlock', async (agent, type, closeness, range) => { + perform: runAsAction(async (agent, type, closeness, range) => { await skills.goToNearestBlock(agent.bot, type, closeness, range); }) }, @@ -104,7 +114,7 @@ export const actionsList = [ name: '!moveAway', description: 'Move away from the current location in any direction by a given distance.', params: {'distance': { type: 'float', description: 'The distance to move away.', domain: [0, Infinity] }}, - perform: runAsAction('moveAway', async (agent, distance) => { + perform: runAsAction(async (agent, distance) => { await skills.moveAway(agent.bot, distance); }) }, @@ -122,7 +132,7 @@ export const actionsList = [ name: '!goToPlace', description: 'Go to a saved location.', params: {'name': { type: 'string', description: 'The name of the location to go to.' }}, - perform: runAsAction('goToPlace', async (agent, name) => { + perform: runAsAction(async (agent, name) => { const pos = agent.memory_bank.recallPlace(name); if (!pos) { skills.log(agent.bot, `No location named "${name}" saved.`); @@ -139,7 +149,7 @@ export const actionsList = [ 'item_name': { type: 'ItemName', description: 'The name of the item to give.' }, 'num': { type: 'int', description: 'The number of items to give.', domain: [1, Number.MAX_SAFE_INTEGER] } }, - perform: runAsAction('givePlayer', async (agent, player_name, item_name, num) => { + perform: runAsAction(async (agent, player_name, item_name, num) => { await skills.giveToPlayer(agent.bot, item_name, player_name, num); }) }, @@ -147,7 +157,7 @@ export const actionsList = [ name: '!consume', description: 'Eat/drink the given item.', params: {'item_name': { type: 'ItemName', description: 'The name of the item to consume.' }}, - perform: runAsAction('consume', async (agent, item_name) => { + perform: runAsAction(async (agent, item_name) => { await agent.bot.consume(item_name); skills.log(agent.bot, `Consumed ${item_name}.`); }) @@ -156,7 +166,7 @@ export const actionsList = [ name: '!equip', description: 'Equip the given item.', params: {'item_name': { type: 'ItemName', description: 'The name of the item to equip.' }}, - perform: runAsAction('equip', async (agent, item_name) => { + perform: runAsAction(async (agent, item_name) => { await skills.equip(agent.bot, item_name); }) }, @@ -167,7 +177,7 @@ export const actionsList = [ 'item_name': { type: 'ItemName', description: 'The name of the item to put in the chest.' }, 'num': { type: 'int', description: 'The number of items to put in the chest.', domain: [1, Number.MAX_SAFE_INTEGER] } }, - perform: runAsAction('putInChest', async (agent, item_name, num) => { + perform: runAsAction(async (agent, item_name, num) => { await skills.putInChest(agent.bot, item_name, num); }) }, @@ -178,7 +188,7 @@ export const actionsList = [ 'item_name': { type: 'ItemName', description: 'The name of the item to take.' }, 'num': { type: 'int', description: 'The number of items to take.', domain: [1, Number.MAX_SAFE_INTEGER] } }, - perform: runAsAction('takeFromChest', async (agent, item_name, num) => { + perform: runAsAction(async (agent, item_name, num) => { await skills.takeFromChest(agent.bot, item_name, num); }) }, @@ -186,7 +196,7 @@ export const actionsList = [ name: '!viewChest', description: 'View the items/counts of the nearest chest.', params: { }, - perform: runAsAction('viewChest', async (agent) => { + perform: runAsAction(async (agent) => { await skills.viewChest(agent.bot); }) }, @@ -197,7 +207,7 @@ export const actionsList = [ 'item_name': { type: 'ItemName', description: 'The name of the item to discard.' }, 'num': { type: 'int', description: 'The number of items to discard.', domain: [1, Number.MAX_SAFE_INTEGER] } }, - perform: runAsAction('discard', async (agent, item_name, num) => { + perform: runAsAction(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); @@ -211,7 +221,7 @@ export const actionsList = [ 'type': { type: 'BlockName', description: 'The block type to collect.' }, 'num': { type: 'int', description: 'The number of blocks to collect.', domain: [1, Number.MAX_SAFE_INTEGER] } }, - perform: runAsAction('collectBlocks', async (agent, type, num) => { + perform: runAsAction(async (agent, type, num) => { await skills.collectBlock(agent.bot, type, num); }, false, 10) // 10 minute timeout }, @@ -221,7 +231,7 @@ export const actionsList = [ params: { 'type': { type: 'BlockName', description: 'The block type to collect.' } }, - perform: runAsAction('collectAllBlocks', async (agent, type) => { + perform: runAsAction(async (agent, type) => { let success = await skills.collectBlock(agent.bot, type, 1); if (!success) agent.actions.cancelResume(); @@ -234,7 +244,7 @@ export const actionsList = [ 'recipe_name': { type: 'ItemName', description: 'The name of the output item to craft.' }, 'num': { type: 'int', description: 'The number of times to craft the recipe. This is NOT the number of output items, as it may craft many more items depending on the recipe.', domain: [1, Number.MAX_SAFE_INTEGER] } }, - perform: runAsAction('craftRecipe', async (agent, recipe_name, num) => { + perform: runAsAction(async (agent, recipe_name, num) => { await skills.craftRecipe(agent.bot, recipe_name, num); }) }, @@ -245,7 +255,7 @@ export const actionsList = [ 'item_name': { type: 'ItemName', description: 'The name of the input item to smelt.' }, 'num': { type: 'int', description: 'The number of times to smelt the item.', domain: [1, Number.MAX_SAFE_INTEGER] } }, - perform: runAsAction('smeltItem', async (agent, item_name, num) => { + perform: runAsAction(async (agent, item_name, num) => { let response = await skills.smeltItem(agent.bot, item_name, num); if (response.indexOf('Successfully') !== -1) { // there is a bug where the bot's inventory is not updated after smelting @@ -259,7 +269,7 @@ export const actionsList = [ name: '!clearFurnace', description: 'Take all items out of the nearest furnace.', params: { }, - perform: runAsAction('clearFurnace', async (agent) => { + perform: runAsAction(async (agent) => { await skills.clearNearestFurnace(agent.bot); }) }, @@ -267,7 +277,7 @@ export const actionsList = [ name: '!placeHere', description: 'Place a given block in the current location. Do NOT use to build structures, only use for single blocks/torches.', params: {'type': { type: 'BlockName', description: 'The block type to place.' }}, - perform: runAsAction('placeHere', async (agent, type) => { + perform: runAsAction(async (agent, type) => { let pos = agent.bot.entity.position; await skills.placeBlock(agent.bot, type, pos.x, pos.y, pos.z); }) @@ -276,14 +286,14 @@ export const actionsList = [ name: '!attack', description: 'Attack and kill the nearest entity of a given type.', params: {'type': { type: 'string', description: 'The type of entity to attack.'}}, - perform: runAsAction('attack', async (agent, type) => { + perform: runAsAction(async (agent, type) => { await skills.attackNearest(agent.bot, type, true); }) }, { name: '!goToBed', description: 'Go to the nearest bed and sleep.', - perform: runAsAction('goToBed', async (agent) => { + perform: runAsAction(async (agent) => { await skills.goToBed(agent.bot); }) }, @@ -291,7 +301,7 @@ export const actionsList = [ name: '!activate', description: 'Activate the nearest object of a given type.', params: {'type': { type: 'BlockName', description: 'The type of object to activate.' }}, - perform: runAsAction('activate', async (agent, type) => { + perform: runAsAction(async (agent, type) => { await skills.activateNearestBlock(agent.bot, type); }) }, @@ -299,7 +309,7 @@ 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: runAsAction('stay', async (agent, seconds) => { + perform: runAsAction(async (agent, seconds) => { await skills.stay(agent.bot, seconds); }) }, diff --git a/src/agent/modes.js b/src/agent/modes.js index f3005c7..f86603a 100644 --- a/src/agent/modes.js +++ b/src/agent/modes.js @@ -162,7 +162,7 @@ const modes = [ { name: 'item_collecting', description: 'Collect nearby items when idle.', - interrupts: ['followPlayer'], + interrupts: ['action:followPlayer'], on: true, active: false, @@ -193,7 +193,7 @@ const modes = [ { name: 'torch_placing', description: 'Place torches when idle and there are no torches nearby.', - interrupts: ['followPlayer'], + interrupts: ['action:followPlayer'], on: true, active: false, cooldown: 5, @@ -328,7 +328,7 @@ class ModeController { this.unPauseAll(); } for (let mode of this.modes_list) { - let interruptible = mode.interrupts.some(i => i === 'all') || mode.interrupts.some(i => `action:${i}` === this.agent.actions.currentActionLabel); + let interruptible = mode.interrupts.some(i => i === 'all') || mode.interrupts.some(i => i === this.agent.actions.currentActionLabel); if (mode.on && !mode.paused && !mode.active && (this.agent.isIdle() || interruptible)) { await mode.update(this.agent); }