diff --git a/src/agent/library/skills.js b/src/agent/library/skills.js index a3732b9..700cbb7 100644 --- a/src/agent/library/skills.js +++ b/src/agent/library/skills.js @@ -359,11 +359,13 @@ export async function collectBlock(bot, blockType, num=1, exclude=null) { let blocktypes = [blockType]; if (blockType.endsWith('ore')) blocktypes.push('deepslate_'+blockType); + if (blockType === 'dirt') + blocktypes.push('grass_block'); let collected = 0; for (let i=0; i= count) + if (count !== null && blocks.length >= count) break; } } diff --git a/src/agent/npc/build_goal.js b/src/agent/npc/build_goal.js index e496a30..27fc3c2 100644 --- a/src/agent/npc/build_goal.js +++ b/src/agent/npc/build_goal.js @@ -17,6 +17,13 @@ export class BuildGoal { if (orientation === 3) return [sizez-z-1, x]; } + async wrapSkill(func) { + if (!this.agent.isIdle()) + return false; + let res = await this.agent.coder.execute(func); + return !res.interrupted; + } + async executeNext(goal, position=null, orientation=null) { let sizex = goal.blocks[0][0].length; let sizez = goal.blocks[0].length; @@ -47,32 +54,28 @@ export class BuildGoal { let current_block = this.agent.bot.blockAt(world_pos); let res = null; - if (!blockSatisfied(block_name, current_block)) { + if (current_block !== null && !blockSatisfied(block_name, current_block)) { acted = true; - if (!this.agent.isIdle()) - return {missing: missing, acted: acted, position: position, orientation: orientation}; - res = await this.agent.coder.execute(async () => { - await skills.breakBlockAt(this.agent.bot, world_pos.x, world_pos.y, world_pos.z); - }); - if (res.interrupted) - return {missing: missing, acted: acted, position: position, orientation: orientation}; - - let block_typed = getTypeOfGeneric(this.agent.bot, block_name); - if (inventory[block_typed] > 0) { - - if (!this.agent.isIdle()) - return {missing: missing, acted: acted, position: position, orientation: orientation}; - await this.agent.coder.execute(async () => { - await skills.placeBlock(this.agent.bot, block_typed, world_pos.x, world_pos.y, world_pos.z); + if (current_block.name !== 'air') { + res = await this.wrapSkill(async () => { + await skills.breakBlockAt(this.agent.bot, world_pos.x, world_pos.y, world_pos.z); }); - if (res.interrupted) - return {missing: missing, acted: acted, position: position, orientation: orientation}; + if (!res) return {missing: missing, acted: acted, position: position, orientation: orientation}; + } - } else { - if (missing[block_typed] === undefined) - missing[block_typed] = 0; - missing[block_typed]++; + if (block_name !== 'air') { + let block_typed = getTypeOfGeneric(this.agent.bot, block_name); + if (inventory[block_typed] > 0) { + res = await this.wrapSkill(async () => { + await skills.placeBlock(this.agent.bot, block_typed, world_pos.x, world_pos.y, world_pos.z); + }); + if (!res) return {missing: missing, acted: acted, position: position, orientation: orientation}; + } else { + if (missing[block_typed] === undefined) + missing[block_typed] = 0; + missing[block_typed]++; + } } } } diff --git a/src/agent/npc/controller.js b/src/agent/npc/controller.js index 76c432c..1ac20ba 100644 --- a/src/agent/npc/controller.js +++ b/src/agent/npc/controller.js @@ -10,11 +10,30 @@ export class NPCContoller { this.agent = agent; this.data = NPCData.fromObject(agent.prompter.prompts.npc); this.temp_goals = []; - this.item_goal = new ItemGoal(agent); + this.item_goal = new ItemGoal(agent, this.data); this.build_goal = new BuildGoal(agent); this.constructions = {}; } + getBuiltPositions() { + let positions = []; + for (let name in this.data.built) { + let position = this.data.built[name].position; + let offset = this.constructions[name].offset; + let sizex = this.constructions[name].blocks[0][0].length; + let sizez = this.constructions[name].blocks[0].length; + let sizey = this.constructions[name].blocks.length; + for (let y = offset; y < sizey+offset; y++) { + for (let z = 0; z < sizez; z++) { + for (let x = 0; x < sizex; x++) { + positions.push({x: position.x + x, y: position.y + y, z: position.z + z}); + } + } + } + } + return positions; + } + init() { if (this.data === null) return; @@ -80,5 +99,8 @@ export class NPCContoller { if (res.acted) break; } } + + if (this.agent.isIdle()) + this.agent.bot.emit('idle'); } } \ No newline at end of file diff --git a/src/agent/npc/item_goal.js b/src/agent/npc/item_goal.js index dea4a53..0c89ce8 100644 --- a/src/agent/npc/item_goal.js +++ b/src/agent/npc/item_goal.js @@ -152,7 +152,7 @@ class ItemNode { let inventory = world.getInventoryCounts(this.manager.agent.bot); let init_quantity = inventory[this.name] || 0; if (this.type === 'block') { - await skills.collectBlock(this.manager.agent.bot, this.source, quantity); + await skills.collectBlock(this.manager.agent.bot, this.source, quantity, this.manager.agent.npc.getBuiltPositions()); } else if (this.type === 'smelt') { let to_smelt_name = this.recipe[0].node.name; let to_smelt_quantity = Math.min(quantity, inventory[to_smelt_name] || 1); @@ -210,10 +210,13 @@ class ItemWrapper { } } - let block_source = mc.getItemBlockSource(this.name); - if (block_source) { - let tool = mc.getBlockTool(block_source); - this.add_method(new ItemNode(this.manager, this, this.name).setCollectable(block_source, tool)); + let block_sources = mc.getItemBlockSources(this.name); + if (block_sources.length > 0 && this.name !== 'torch') { // Do not collect placed torches + for (let block_source of block_sources) { + if (block_source === 'grass_block') continue; // Dirt nodes will collect grass blocks + let tool = mc.getBlockTool(block_source); + this.add_method(new ItemNode(this.manager, this, this.name).setCollectable(block_source, tool)); + } } let smeltingIngredient = mc.getItemSmeltingIngredient(this.name); diff --git a/src/utils/mcdata.js b/src/utils/mcdata.js index 6242e61..9908649 100644 --- a/src/utils/mcdata.js +++ b/src/utils/mcdata.js @@ -171,14 +171,15 @@ export function getItemSmeltingIngredient(itemName) { }[itemName]; } -export function getItemBlockSource(itemName) { +export function getItemBlockSources(itemName) { let itemId = getItemId(itemName); + let sources = []; for (let block of getAllBlocks()) { if (block.drops.includes(itemId)) { - return block.name; + sources.push(block.name); } } - return null; + return sources; } export function getItemAnimalSource(itemName) {