From 79435f85b5164d1122cfed4bb69d93f6069118f1 Mon Sep 17 00:00:00 2001 From: MaxRobinsonTheGreat Date: Sun, 21 Apr 2024 12:50:36 -0500 Subject: [PATCH 1/6] can choose which side to place block on --- andy.json | 4 ++-- src/agent/library/skills.js | 33 ++++++++++++++++++++++++++++----- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/andy.json b/andy.json index f1584f5..14791a8 100644 --- a/andy.json +++ b/andy.json @@ -135,8 +135,8 @@ {"role": "assistant", "content": "I found an oak log and I am now standing next to it. What next?"} ], [ - {"role": "user", "content": "234jeb: build a little tower"}, - {"role": "assistant", "content": "```let pos = bot.entity.position;\nfor (let i = 0; i < 5; i++) {\n await skills.placeBlock(bot, 'dirt', pos.x, pos.y + i, pos.z);\n}\n```"}, + {"role": "user", "content": "234jeb: build a little tower with a torch on the side"}, + {"role": "assistant", "content": "```let pos = bot.entity.position;\nfor (let i = 0; i < 5; i++) {\n await skills.placeBlock(bot, 'dirt', pos.x, pos.y + i, pos.z);\n}\nawait skills.placeBlock(bot, 'torch', pos.x + 1, pos.y + 4, pos.z, 'side');\n```"}, {"role": "system", "content": "Successfully placed 5 dirt."}, {"role": "assistant", "content": "I built a little tower!"} ], diff --git a/src/agent/library/skills.js b/src/agent/library/skills.js index f72b785..2abb082 100644 --- a/src/agent/library/skills.js +++ b/src/agent/library/skills.js @@ -477,7 +477,7 @@ export async function breakBlockAt(bot, x, y, z) { } -export async function placeBlock(bot, blockType, x, y, z) { +export async function placeBlock(bot, blockType, x, y, z, placeOn='bottom') { /** * Place the given block type at the given position. It will build off from any adjacent blocks. Will fail if there is a block in the way or nothing to build off of. * @param {MinecraftBot} bot, reference to the minecraft bot. @@ -485,10 +485,12 @@ export async function placeBlock(bot, blockType, x, y, z) { * @param {number} x, the x coordinate of the block to place. * @param {number} y, the y coordinate of the block to place. * @param {number} z, the z coordinate of the block to place. + * @param {string} placeOn, the preferred side of the block to place on. Can be 'top', 'bottom', 'north', 'south', 'east', 'west', or 'side'. Defaults to bottom. Will place on first available side if not possible. * @returns {Promise} true if the block was placed, false otherwise. * @example - * let position = world.getPosition(bot); - * await skills.placeBlock(bot, "oak_log", position.x + 1, position.y - 1, position.x); + * let p = world.getPosition(bot); + * await skills.placeBlock(bot, "oak_log", p.x + 2, p.y, p.x); + * await skills.placeBlock(bot, "torch", p.x + 1, p.y, p.x, 'side'); **/ console.log('placing block...') let block = bot.inventory.items().find(item => item.name === blockType); @@ -516,12 +518,33 @@ export async function placeBlock(bot, blockType, x, y, z) { // get the buildoffblock and facevec based on whichever adjacent block is not empty let buildOffBlock = null; let faceVec = null; - const dirs = [Vec3(0, -1, 0), Vec3(0, 1, 0), Vec3(1, 0, 0), Vec3(-1, 0, 0), Vec3(0, 0, 1), Vec3(0, 0, -1)]; + // const dirs = [Vec3(0, -1, 0), Vec3(0, 1, 0), Vec3(1, 0, 0), Vec3(-1, 0, 0), Vec3(0, 0, 1), Vec3(0, 0, -1)]; + const dir_map = { + 'top': Vec3(0, 1, 0), + 'bottom': Vec3(0, -1, 0), + 'north': Vec3(0, 0, -1), + 'south': Vec3(0, 0, 1), + 'east': Vec3(1, 0, 0), + 'west': Vec3(-1, 0, 0), + } + let dirs = []; + if (placeOn === 'side') { + dirs.push(dir_map['north'], dir_map['south'], dir_map['east'], dir_map['west']); + } + else if (dir_map[placeOn] !== undefined) { + dirs.push(dir_map[placeOn]); + } + else { + dirs.push(dir_map['bottom']); + log(bot, `Unknown placeOn value "${placeOn}". Defaulting to bottom.`); + } + dirs.push(...Object.values(dir_map).filter(d => !dirs.includes(d))); + for (let d of dirs) { const block = bot.blockAt(target_dest.plus(d)); if (!empty_blocks.includes(block.name)) { buildOffBlock = block; - faceVec = new Vec3(-d.x, -d.y, -d.z); + faceVec = new Vec3(-d.x, -d.y, -d.z); // invert break; } } From 30c7cc25a0e987890de8dd773b4680115ac46740 Mon Sep 17 00:00:00 2001 From: MaxRobinsonTheGreat Date: Sun, 21 Apr 2024 12:50:54 -0500 Subject: [PATCH 2/6] auto remove iife from code --- src/agent/coder.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/agent/coder.js b/src/agent/coder.js index 0551032..65855e8 100644 --- a/src/agent/coder.js +++ b/src/agent/coder.js @@ -54,6 +54,28 @@ export class Coder { return await import('../..' + this.fp + filename); } + + removeIIFE(codeString) { + // This function attempts to remove IIFE (Immediately Invoked Function Expression) patterns from generated code. + // ex of IIFE: (async () => {console.log('hello');})() + // IIFEs break the await pattern we use, where behaviors continue running after the code has "finished" executing + // This is actually a pretty big issue, as there is no way to force the code to be awaited, but this is a simple fix for now. + const iifePatterns = [ + /^\s*\(\s*async\s*\(\s*\)\s*=>\s*{([\s\S]*?)}\s*\)\s*\(\s*\)\s*;?\s*$/, // AI generated regex + /^\s*\(\s*async\s+function\s*\(\s*\)\s*{([\s\S]*?)}\s*\)\s*\(\s*\)\s*;?\s*$/, + ]; // will not catch nested IIFEs, ones with arguments, or ones that are not async + + for (const pattern of iifePatterns) { + const match = codeString.match(pattern); + if (match) { + console.warn('IIFE detected in generated code. Attempted automatic fix.'); + return match[1].trim(); + } + } + + return codeString.trim(); + } + sanitizeCode(code) { code = code.trim(); const remove_strs = ['Javascript', 'javascript', 'js'] @@ -63,6 +85,7 @@ export class Coder { return code; } } + code = this.removeIIFE(code); return code; } From 7e71f12026f1dde391edce5b261f17ff9ff4553b Mon Sep 17 00:00:00 2001 From: MaxRobinsonTheGreat Date: Sat, 22 Jun 2024 15:35:18 -0500 Subject: [PATCH 3/6] will now give self item in creative mode --- package.json | 1 + src/agent/library/skills.js | 6 +++++- src/agent/library/world.js | 2 ++ src/utils/mcdata.js | 7 ++++++- 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index b2912b1..79829e4 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "mineflayer-pvp": "^1.3.2", "openai": "^4.4.0", "patch-package": "^8.0.0", + "prismarine-item": "^1.14.0", "replicate": "^0.29.4", "vec3": "^0.1.10", "yargs": "^17.7.2" diff --git a/src/agent/library/skills.js b/src/agent/library/skills.js index 1dbe0fb..8e8411f 100644 --- a/src/agent/library/skills.js +++ b/src/agent/library/skills.js @@ -525,7 +525,7 @@ export async function placeBlock(bot, blockType, x, y, z, placeOn='bottom', dont blockType += `[facing=${face}]`; } } - if (blockType === 'repeater' || blockType === 'comparator') { + if (blockType === 'ladder' || blockType === 'repeater' || blockType === 'comparator') { blockType += `[facing=${face}]`; } @@ -540,6 +540,10 @@ export async function placeBlock(bot, blockType, x, y, z, placeOn='bottom', dont } let block = bot.inventory.items().find(item => item.name === blockType); + if (!block && bot.game.gameMode === 'creative') { + await bot.creative.setInventorySlot(36, mc.makeItem(blockType, 1)); // 36 is first hotbar slot + block = bot.inventory.items().find(item => item.name === blockType); + } if (!block) { log(bot, `Don't have any ${blockType} to place.`); return false; diff --git a/src/agent/library/world.js b/src/agent/library/world.js index 0e32014..dc64599 100644 --- a/src/agent/library/world.js +++ b/src/agent/library/world.js @@ -261,6 +261,8 @@ export function shouldPlaceTorch(bot) { const pos = getPosition(bot); // TODO: check light level instead of nearby torches, block.light is broken let nearest_torch = getNearestBlock(bot, 'torch', 6); + if (!nearest_torch) + nearest_torch = getNearestBlock(bot, 'wall_torch', 6); if (!nearest_torch) { const block = bot.blockAt(pos); let has_torch = bot.inventory.items().find(item => item.name === 'torch'); diff --git a/src/utils/mcdata.js b/src/utils/mcdata.js index ad83963..c260325 100644 --- a/src/utils/mcdata.js +++ b/src/utils/mcdata.js @@ -1,6 +1,7 @@ import minecraftData from 'minecraft-data'; import settings from '../../settings.js'; import { createBot } from 'mineflayer'; +import prismarine_items from 'prismarine-item'; import { pathfinder } from 'mineflayer-pathfinder'; import { plugin as pvp } from 'mineflayer-pvp'; import { plugin as collectblock } from 'mineflayer-collectblock'; @@ -10,7 +11,7 @@ const armorManager = plugin; const mc_version = settings.minecraft_version; const mcdata = minecraftData(mc_version); - +const Item = prismarine_items(mc_version); export const WOOD_TYPES = ['oak', 'spruce', 'birch', 'jungle', 'acacia', 'dark_oak']; export const MATCHING_WOOD_BLOCKS = [ @@ -236,4 +237,8 @@ export function getBlockTool(blockName) { return null; } return getItemName(Object.keys(block.harvestTools)[0]); // Double check first tool is always simplest +} + +export function makeItem(name, amount=1) { + return new Item(getItemId(name), amount); } \ No newline at end of file From fb587d759aee2f66724cb087f5c279a56fa9205c Mon Sep 17 00:00:00 2001 From: MaxRobinsonTheGreat Date: Sat, 22 Jun 2024 16:04:49 -0500 Subject: [PATCH 4/6] fixed door placement --- src/agent/library/skills.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/agent/library/skills.js b/src/agent/library/skills.js index 8e8411f..47e4a8c 100644 --- a/src/agent/library/skills.js +++ b/src/agent/library/skills.js @@ -532,7 +532,7 @@ export async function placeBlock(bot, blockType, x, y, z, placeOn='bottom', dont let msg = '/setblock ' + Math.floor(x) + ' ' + Math.floor(y) + ' ' + Math.floor(z) + ' ' + blockType; bot.chat(msg); if (blockType.includes('door')) - bot.chat('/setblock ' + Math.floor(x) + ' ' + Math.floor(y+1) + ' ' + Math.floor(z) + ' ' + blockType + '[half=top]'); + bot.chat('/setblock ' + Math.floor(x) + ' ' + Math.floor(y+1) + ' ' + Math.floor(z) + ' ' + blockType + '[half=upper]'); if (blockType.includes('bed')) bot.chat('/setblock ' + Math.floor(x) + ' ' + Math.floor(y) + ' ' + Math.floor(z-1) + ' ' + blockType + '[part=head]'); log(bot, `Used /setblock to place ${blockType} at ${target_dest}.`); From 09e46fc63be1a84f91d7c3ee643c8c9cb6d340a3 Mon Sep 17 00:00:00 2001 From: MaxRobinsonTheGreat Date: Sat, 22 Jun 2024 16:09:41 -0500 Subject: [PATCH 5/6] removed iife removal --- src/agent/coder.js | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/src/agent/coder.js b/src/agent/coder.js index 253578b..d408b6c 100644 --- a/src/agent/coder.js +++ b/src/agent/coder.js @@ -54,28 +54,6 @@ export class Coder { return await import('../..' + this.fp + filename); } - - removeIIFE(codeString) { - // This function attempts to remove IIFE (Immediately Invoked Function Expression) patterns from generated code. - // ex of IIFE: (async () => {console.log('hello');})() - // IIFEs break the await pattern we use, where behaviors continue running after the code has "finished" executing - // This is actually a pretty big issue, as there is no way to force the code to be awaited, but this is a simple fix for now. - const iifePatterns = [ - /^\s*\(\s*async\s*\(\s*\)\s*=>\s*{([\s\S]*?)}\s*\)\s*\(\s*\)\s*;?\s*$/, // AI generated regex - /^\s*\(\s*async\s+function\s*\(\s*\)\s*{([\s\S]*?)}\s*\)\s*\(\s*\)\s*;?\s*$/, - ]; // will not catch nested IIFEs, ones with arguments, or ones that are not async - - for (const pattern of iifePatterns) { - const match = codeString.match(pattern); - if (match) { - console.warn('IIFE detected in generated code. Attempted automatic fix.'); - return match[1].trim(); - } - } - - return codeString.trim(); - } - sanitizeCode(code) { code = code.trim(); const remove_strs = ['Javascript', 'javascript', 'js'] @@ -85,7 +63,6 @@ export class Coder { return code; } } - code = this.removeIIFE(code); return code; } From e1e1b3d20eeb236bc919cfa1a4ce613e0e1fd452 Mon Sep 17 00:00:00 2001 From: MaxRobinsonTheGreat Date: Sat, 22 Jun 2024 16:11:17 -0500 Subject: [PATCH 6/6] remove comment --- src/agent/library/skills.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/agent/library/skills.js b/src/agent/library/skills.js index 47e4a8c..47f4d1a 100644 --- a/src/agent/library/skills.js +++ b/src/agent/library/skills.js @@ -567,7 +567,6 @@ export async function placeBlock(bot, blockType, x, y, z, placeOn='bottom', dont // get the buildoffblock and facevec based on whichever adjacent block is not empty let buildOffBlock = null; let faceVec = null; - // const dirs = [Vec3(0, -1, 0), Vec3(0, 1, 0), Vec3(1, 0, 0), Vec3(-1, 0, 0), Vec3(0, 0, 1), Vec3(0, 0, -1)]; const dir_map = { 'top': Vec3(0, 1, 0), 'bottom': Vec3(0, -1, 0),