Merge pull request #9 from kolbytn/crafting

Crafting
This commit is contained in:
Max Robinson 2023-11-19 14:39:21 -06:00 committed by GitHub
commit 906c7c32ad
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 70 additions and 67 deletions

View file

@ -3,6 +3,7 @@ import { writeFile, readFile, unlink } from 'fs';
export class Coder {
constructor(agent) {
this.agent = agent;
this.queued_code = '';
this.current_code = '';
this.file_counter = 0;
this.fp = './agent_code/';
@ -19,7 +20,7 @@ export class Coder {
}
queueCode(code) {
this.current_code = this.santitizeCode(code);
this.queued_code = this.santitizeCode(code);
}
santitizeCode(code) {
@ -30,15 +31,9 @@ export class Coder {
return code;
}
}
// this may cause problems in callback functions
code = code.replaceAll(';\n', '; if(bot.interrupt_code) {log(bot, "Code interrupted.");return;}\n');
return code;
}
hasCode() {
return this.current_code.length > 0;
}
writeFilePromise(filename, src) {
// makes it so we can await this function
return new Promise((resolve, reject) => {
@ -55,10 +50,12 @@ export class Coder {
// returns {success: bool, message: string, interrupted: bool}
async execute() {
if (!this.current_code) return {success: false, message: "No code to execute.", interrupted: false};
if (!this.queued_code) return {success: false, message: "No code to execute.", interrupted: false};
if (!this.code_template) return {success: false, message: "Code template not loaded.", interrupted: false};
let src = '';
for (let line of this.current_code.split('\n')) {
// this may cause problems in callback functions
let code = this.queued_code.replaceAll(';\n', '; if(bot.interrupt_code) {log(bot, "Code interrupted.");return;}\n');
for (let line of code.split('\n')) {
src += ` ${line}\n`;
}
src = this.code_template.replace('/* CODE HERE */', src);
@ -86,7 +83,8 @@ export class Coder {
console.log('executing code...\n');
let execution_file = await import('.'+filename);
await this.stop();
this.current_code = this.queued_code;
this.executing = true;
await execution_file.main(this.agent.bot);
this.executing = false;

View file

@ -1,6 +1,6 @@
import { readFileSync } from 'fs';
import { getCraftingTable, getNearbyMobTypes, getNearbyPlayerNames, getNearbyBlockTypes, getInventoryCounts } from './world.js';
import { getNearestBlock, getNearbyMobTypes, getNearbyPlayerNames, getNearbyBlockTypes, getInventoryCounts } from './world.js';
import { getAllItems } from './mcdata.js';
@ -23,7 +23,7 @@ export function getInventory(bot) {
let inventory = getInventoryCounts(bot);
let res = 'INVENTORY';
for (const item in inventory) {
if (inventory[item] > 0)
if (inventory[item] && inventory[item] > 0)
res += `\n- ${item}: ${inventory[item]}`;
}
if (res == 'INVENTORY') {
@ -62,7 +62,7 @@ export function getNearbyEntities(bot) {
export function getCraftable(bot) {
const table = getCraftingTable(bot);
const table = getNearestBlock(bot, 'crafting_table');
let res = 'CRAFTABLE_ITEMS';
for (const item of getAllItems()) {
let recipes = bot.recipesFor(item.id, null, 1, table);

View file

@ -25,11 +25,6 @@
{"role": "assistant", "content": "Here!"}
],
[
{"role": "user", "content": "sarah_O.o: can you fly up in the air?"},
{"role": "assistant", "content": "I can't do that."}
],
[
{"role": "user", "content": "joe: Follow me!"},
{"role": "assistant", "content": "Sure!\n```\n// I am going to follow joe.\nawait skills.followPlayer(bot, 'joe');\n```"}
@ -45,5 +40,12 @@
[
{"role": "user", "content": "billybob: stop"},
{"role": "assistant", "content": "```\n// I am going to write empty code to stop whatever I am doing\n```"}
],
[
{"role": "user", "content": "maya: go to the nearest oak log"},
{"role": "assistant", "content": "```\n// I am navigating to the nearest oak log.\nawait skills.goToPosition(bot, nearestOakLog.x, nearestOakLog.y, nearestOakLog.z);\n```"},
{"role": "system", "content": "Code output:\n!!Code threw exception!! Error: ReferenceError: nearestOakLog is not defined\n Write code to fix the problem and try again."},
{"role": "assistant", "content": "Apologies, I made an error. Let me try that again.```\n// I am navigating to the nearest oak log.\nlet position = world.getNearestBlock(bot, 'oak_log', 20);\nawait skills.goToPosition(bot, position.x, position.y, position.z);\n```"}
]
]

View file

@ -63,7 +63,7 @@ export class History {
if (this.memory != '') {
memory_prompt += ' Include information from your previous memory if it is still relevant. Your output will replace your previous memory.';
}
memory_prompt += ' Your output should use one of the following formats:\n';
memory_prompt += ' Your output should be a brief list of things you have learned using the following formats:\n';
memory_prompt += '- When the player... output...\n';
memory_prompt += '- I learned that player [name]...\n';
@ -85,7 +85,7 @@ export class History {
for (let example of examples) {
let messages = '';
for (let turn of example) {
if (turn.role == 'user')
if (turn.role != 'assistant')
messages += turn.content.substring(turn.content.indexOf(':')+1).trim() + '\n';
}
messages = messages.trim();
@ -97,7 +97,7 @@ export class History {
async setExamples() {
let messages = '';
for (let turn of this.turns) {
if (turn.role == 'user')
if (turn.role != 'assistant')
messages += turn.content.substring(turn.content.indexOf(':')+1).trim() + '\n';
}
messages = messages.trim();

View file

@ -23,6 +23,9 @@ export function getItemId(item) {
return mcdata.itemsByName[item].id;
}
export function getItemName(itemId) {
return mcdata.items[itemId].name;
}
export function getAllItems(ignore) {
if (!ignore) {

View file

@ -1,5 +1,5 @@
import { getItemId } from "./mcdata.js";
import { getCraftingTable, getInventoryCounts, getInventoryStacks, getNearbyMobs, getNearbyBlocks } from "./world.js";
import { getNearestBlock, getInventoryCounts, getInventoryStacks, getNearbyMobs, getNearbyBlocks } from "./world.js";
import pf from 'mineflayer-pathfinder';
import Vec3 from 'vec3';
@ -8,18 +8,36 @@ export function log(bot, message) {
}
export async function craftItem(bot, itemName) {
export async function craftItem(bot, itemName, num=1) {
/**
* Attempt to craft the given item.
* @param {MinecraftBot} bot, reference to the minecraft bot.
* @param {string} item_name, the item name to craft.
* @param {number} num, the number of items to craft. Defaults to 1.
* @returns {Promise<boolean>} true if the item was crafted, false otherwise.
* @example
* await skills.craftItem(bot, "wooden_pickaxe");
* await skills.craftItem(bot, "wooden_pickaxe", 2);
**/
const table = getCraftingTable(bot);
let recipes = bot.recipesFor(getItemId(itemName), null, 1, table);
await bot.craft(recipes[0], 1, null);
let recipes = bot.recipesFor(getItemId(itemName), null, num, null); // get recipes that don't require a crafting table
let craftingTable = undefined;
if (!recipes || recipes.length === 0) {
craftingTable = getNearestBlock(bot, 'crafting_table', 6);
if (craftingTable === null){
log(bot, `You either do not have enough resources to craft ${itemName} or it requires a crafting table, but there is none nearby.`)
return false;
}
recipes = bot.recipesFor(getItemId(itemName), null, num, craftingTable);
}
if (!recipes || recipes.length === 0) {
log(bot, `You do not have the resources to craft ${num} ${itemName}(s).`);
return false;
}
const recipe = recipes[0];
console.log('crafting...');
await bot.craft(recipe, num, craftingTable);
console.log('crafted');
return true;
}
@ -216,7 +234,7 @@ export async function giveToPlayer(bot, itemType, username) {
let player = bot.players[username].entity
if (!player)
return false;
if (getInventoryCounts(bot)[itemType] == 0)
if (!getInventoryCounts(bot)[itemType])
return false;
await goToPlayer(bot, username);
let pos = player.position;

View file

@ -1,16 +1,27 @@
import { getAllBlockIds, getAllBlocks, getAllItems } from './mcdata.js';
import { getAllBlockIds } from './mcdata.js';
export function getCraftingTable(bot) {
const blocks = getNearbyBlocks(bot, 50);
let table = null;
for (const block of blocks) {
if (block.name == 'crafting_table') {
table = block;
break;
}
export function getNearestBlock(bot, block_type, distance=16) {
/**
* Get the position of the nearest block of the given type.
* @param {Bot} bot - The bot to get the nearest block for.
* @param {string} block_type - The name of the block to search for.
* @param {number} distance - The maximum distance to search, default 16.
* @returns {Block} - The nearest block of the given type.
* @example
* let coalBlock = world.getNearestBlock(bot, 'coal_ore', 16);
**/
let block_locs = bot.findBlocks({
matching: (block) => {
return block && block.type === bot.registry.blocksByName[block_type].id
},
maxDistance: distance,
count: 1
});
if (block_locs.length > 0) {
return bot.blockAt(block_locs[0]);
}
return table;
return null;
}
@ -99,16 +110,6 @@ export function getInventoryCounts(bot) {
inventory[item.name] = item.count;
}
}
for (const item of getAllItems()) {
if (!inventory.hasOwnProperty(item.name)) {
inventory[item.name] = 0;
}
}
for (const item of getAllBlocks()) {
if (!inventory.hasOwnProperty(item.name)) {
inventory[item.name] = 0;
}
}
return inventory;
}
@ -181,22 +182,3 @@ export function getNearbyBlockTypes(bot) {
}
return found;
}
export function getNearestBlockPosition(bot, blockType) {
/**
* Get the position of the nearest block of the given type.
* @param {Bot} bot - The bot to get the nearest block for.
* @param {string} blockType - The type of the block to search for.
* @returns {Vec3} - The position of the nearest block of the given type if found else null.
* @example
* let position = world.getNearestBlockPosition(bot, 'coal_ore');
**/
let blocks = getNearbyBlocks(bot, 16);
for (let i = 0; i < blocks.length; i++) {
if (blocks[i].name == blockType) {
return blocks[i].position;
}
}
return null;
}