mirror of
https://github.com/kolbytn/mindcraft.git
synced 2025-04-29 19:44:53 +02:00
refactor and cleanup
This commit is contained in:
parent
287f13c5b5
commit
9ac97d2a37
14 changed files with 143 additions and 172 deletions
|
@ -2,6 +2,5 @@
|
||||||
"name": "andy",
|
"name": "andy",
|
||||||
"bio": "You are playing minecraft and assisting other players in tasks.",
|
"bio": "You are playing minecraft and assisting other players in tasks.",
|
||||||
"memory": "",
|
"memory": "",
|
||||||
"events": [],
|
|
||||||
"turns": []
|
"turns": []
|
||||||
}
|
}
|
|
@ -1,11 +1,10 @@
|
||||||
|
import { History } from './history.js';
|
||||||
|
import { Coder } from './coder.js';
|
||||||
|
import { initModes } from './modes.js';
|
||||||
|
import { Examples } from '../utils/examples.js';
|
||||||
import { initBot } from '../utils/mcdata.js';
|
import { initBot } from '../utils/mcdata.js';
|
||||||
import { sendRequest } from '../utils/gpt.js';
|
import { sendRequest } from '../utils/gpt.js';
|
||||||
import { History } from './history.js';
|
import { containsCommand, commandExists, executeCommand } from './commands/index.js';
|
||||||
import { Examples } from './examples.js';
|
|
||||||
import { Coder } from './coder.js';
|
|
||||||
import { containsCommand, commandExists, executeCommand } from './commands.js';
|
|
||||||
import { Events } from './events.js';
|
|
||||||
import { initModes } from './modes.js';
|
|
||||||
|
|
||||||
|
|
||||||
export class Agent {
|
export class Agent {
|
||||||
|
@ -21,8 +20,6 @@ export class Agent {
|
||||||
|
|
||||||
this.bot = initBot(name);
|
this.bot = initBot(name);
|
||||||
|
|
||||||
this.events = new Events(this, this.history.events);
|
|
||||||
|
|
||||||
initModes(this);
|
initModes(this);
|
||||||
this.idle = true;
|
this.idle = true;
|
||||||
|
|
||||||
|
@ -63,7 +60,7 @@ export class Agent {
|
||||||
this.bot.emit('finished_executing');
|
this.bot.emit('finished_executing');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.startUpdateLoop();
|
this.startEvents();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,7 +127,24 @@ export class Agent {
|
||||||
this.bot.emit('finished_executing');
|
this.bot.emit('finished_executing');
|
||||||
}
|
}
|
||||||
|
|
||||||
startUpdateLoop() {
|
startEvents() {
|
||||||
|
// Custom events
|
||||||
|
this.bot.on('time', () => {
|
||||||
|
if (this.bot.time.timeOfDay == 0)
|
||||||
|
this.bot.emit('sunrise');
|
||||||
|
else if (this.bot.time.timeOfDay == 6000)
|
||||||
|
this.bot.emit('noon');
|
||||||
|
else if (this.bot.time.timeOfDay == 12000)
|
||||||
|
this.bot.emit('sunset');
|
||||||
|
else if (this.bot.time.timeOfDay == 18000)
|
||||||
|
this.bot.emit('midnight');
|
||||||
|
});
|
||||||
|
this.bot.on('health', () => {
|
||||||
|
if (this.bot.health < 20)
|
||||||
|
this.bot.emit('damaged');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Logging callbacks
|
||||||
this.bot.on('error' , (err) => {
|
this.bot.on('error' , (err) => {
|
||||||
console.error('Error event!', err);
|
console.error('Error event!', err);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { writeFile, readFile, mkdirSync } from 'fs';
|
import { writeFile, readFile, mkdirSync } from 'fs';
|
||||||
import { sendRequest } from '../utils/gpt.js';
|
import { sendRequest } from '../utils/gpt.js';
|
||||||
import { getSkillDocs } from './skill-library.js';
|
import { getSkillDocs } from './library/index.js';
|
||||||
import { Examples } from './examples.js';
|
import { Examples } from '../utils/examples.js';
|
||||||
|
|
||||||
|
|
||||||
export class Coder {
|
export class Coder {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as skills from '../skills.js';
|
import * as skills from '../library/skills.js';
|
||||||
import * as world from '../world.js';
|
|
||||||
|
|
||||||
function wrapExecution(func, timeout=-1) {
|
function wrapExecution(func, timeout=-1) {
|
||||||
return async function (agent, ...args) {
|
return async function (agent, ...args) {
|
||||||
|
@ -46,7 +46,7 @@ export const actionsList = [
|
||||||
perform: async function (agent, mode_name, on) {
|
perform: async function (agent, mode_name, on) {
|
||||||
const modes = agent.bot.modes;
|
const modes = agent.bot.modes;
|
||||||
if (!modes.exists(mode_name))
|
if (!modes.exists(mode_name))
|
||||||
return `Mode ${mode_name} does not exist.` + modes.getDocs();
|
return `Mode ${mode_name} does not exist.` + modes.getStr();
|
||||||
if (modes.isOn(mode_name) === on)
|
if (modes.isOn(mode_name) === on)
|
||||||
return `Mode ${mode_name} is already ${on ? 'on' : 'off'}.`;
|
return `Mode ${mode_name} is already ${on ? 'on' : 'off'}.`;
|
||||||
modes.setOn(mode_name, on);
|
modes.setOn(mode_name, on);
|
||||||
|
@ -69,6 +69,14 @@ export const actionsList = [
|
||||||
await skills.followPlayer(agent.bot, player_name);
|
await skills.followPlayer(agent.bot, player_name);
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: '!givePlayer',
|
||||||
|
description: 'Give the specified item to the given player. Ex: !givePlayer("steve", "stone_pickaxe")',
|
||||||
|
params: { 'player_name': '(string) The name of the player to give the item to.', 'item_name': '(string) The name of the item to give.' },
|
||||||
|
perform: wrapExecution(async (agent, player_name, item_name) => {
|
||||||
|
await skills.giveToPlayer(agent.bot, item_name, player_name);
|
||||||
|
})
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: '!collectBlocks',
|
name: '!collectBlocks',
|
||||||
description: 'Collect the nearest blocks of a given type.',
|
description: 'Collect the nearest blocks of a given type.',
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
import { actionsList } from './actions.js';
|
||||||
|
import { queryList } from './queries.js';
|
||||||
|
|
||||||
import { actionsList } from './commands/actions.js';
|
|
||||||
import { queryList } from './commands/queries.js';
|
|
||||||
|
|
||||||
const commandList = queryList.concat(actionsList);
|
const commandList = queryList.concat(actionsList);
|
||||||
const commandMap = {};
|
const commandMap = {};
|
||||||
|
@ -98,4 +98,4 @@ export function getCommandDocs() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return docs + '*\n';
|
return docs + '*\n';
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
import { getNearestBlock, getNearbyEntityTypes, getNearbyPlayerNames, getNearbyBlockTypes, getInventoryCounts } from '../world.js';
|
import * as world from '../library/world.js';
|
||||||
import { getAllItems, getBiomeName } from '../../utils/mcdata.js';
|
import * as mc from '../../utils/mcdata.js';
|
||||||
|
|
||||||
|
|
||||||
const pad = (str) => {
|
const pad = (str) => {
|
||||||
return '\n' + str + '\n';
|
return '\n' + str + '\n';
|
||||||
|
@ -18,7 +19,7 @@ export const queryList = [
|
||||||
res += `\n- Position: x: ${pos.x.toFixed(2)}, y: ${pos.y.toFixed(2)}, z: ${pos.z.toFixed(2)}`;
|
res += `\n- Position: x: ${pos.x.toFixed(2)}, y: ${pos.y.toFixed(2)}, z: ${pos.z.toFixed(2)}`;
|
||||||
res += `\n- Health: ${Math.round(bot.health)} / 20`;
|
res += `\n- Health: ${Math.round(bot.health)} / 20`;
|
||||||
res += `\n- Hunger: ${Math.round(bot.food)} / 20`;
|
res += `\n- Hunger: ${Math.round(bot.food)} / 20`;
|
||||||
res += `\n- Biome: ${getBiomeName(bot)}`;
|
res += `\n- Biome: ${world.getBiomeName(bot)}`;
|
||||||
let weather = "clear";
|
let weather = "clear";
|
||||||
if (bot.rainState > 0)
|
if (bot.rainState > 0)
|
||||||
weather = "Rain";
|
weather = "Rain";
|
||||||
|
@ -45,7 +46,7 @@ export const queryList = [
|
||||||
description: "Get your bot's inventory.",
|
description: "Get your bot's inventory.",
|
||||||
perform: function (agent) {
|
perform: function (agent) {
|
||||||
let bot = agent.bot;
|
let bot = agent.bot;
|
||||||
let inventory = getInventoryCounts(bot);
|
let inventory = world.getInventoryCounts(bot);
|
||||||
let res = 'INVENTORY';
|
let res = 'INVENTORY';
|
||||||
for (const item in inventory) {
|
for (const item in inventory) {
|
||||||
if (inventory[item] && inventory[item] > 0)
|
if (inventory[item] && inventory[item] > 0)
|
||||||
|
@ -63,7 +64,7 @@ export const queryList = [
|
||||||
perform: function (agent) {
|
perform: function (agent) {
|
||||||
let bot = agent.bot;
|
let bot = agent.bot;
|
||||||
let res = 'NEARBY_BLOCKS';
|
let res = 'NEARBY_BLOCKS';
|
||||||
let blocks = getNearbyBlockTypes(bot);
|
let blocks = world.getNearbyBlockTypes(bot);
|
||||||
for (let i = 0; i < blocks.length; i++) {
|
for (let i = 0; i < blocks.length; i++) {
|
||||||
res += `\n- ${blocks[i]}`;
|
res += `\n- ${blocks[i]}`;
|
||||||
}
|
}
|
||||||
|
@ -78,9 +79,9 @@ export const queryList = [
|
||||||
description: "Get the craftable items with the bot's inventory.",
|
description: "Get the craftable items with the bot's inventory.",
|
||||||
perform: function (agent) {
|
perform: function (agent) {
|
||||||
const bot = agent.bot;
|
const bot = agent.bot;
|
||||||
const table = getNearestBlock(bot, 'crafting_table');
|
const table = world.getNearestBlock(bot, 'crafting_table');
|
||||||
let res = 'CRAFTABLE_ITEMS';
|
let res = 'CRAFTABLE_ITEMS';
|
||||||
for (const item of getAllItems()) {
|
for (const item of mc.getAllItems()) {
|
||||||
let recipes = bot.recipesFor(item.id, null, 1, table);
|
let recipes = bot.recipesFor(item.id, null, 1, table);
|
||||||
if (recipes.length > 0) {
|
if (recipes.length > 0) {
|
||||||
res += `\n- ${item.name}`;
|
res += `\n- ${item.name}`;
|
||||||
|
@ -98,10 +99,10 @@ export const queryList = [
|
||||||
perform: function (agent) {
|
perform: function (agent) {
|
||||||
let bot = agent.bot;
|
let bot = agent.bot;
|
||||||
let res = 'NEARBY_ENTITIES';
|
let res = 'NEARBY_ENTITIES';
|
||||||
for (const entity of getNearbyPlayerNames(bot)) {
|
for (const entity of world.getNearbyPlayerNames(bot)) {
|
||||||
res += `\n- player: ${entity}`;
|
res += `\n- player: ${entity}`;
|
||||||
}
|
}
|
||||||
for (const entity of getNearbyEntityTypes(bot)) {
|
for (const entity of world.getNearbyEntityTypes(bot)) {
|
||||||
res += `\n- mob: ${entity}`;
|
res += `\n- mob: ${entity}`;
|
||||||
}
|
}
|
||||||
if (res == 'NEARBY_ENTITIES') {
|
if (res == 'NEARBY_ENTITIES') {
|
||||||
|
@ -114,7 +115,7 @@ export const queryList = [
|
||||||
name: "!modes",
|
name: "!modes",
|
||||||
description: "Get all available modes and see which are on/off.",
|
description: "Get all available modes and see which are on/off.",
|
||||||
perform: function (agent) {
|
perform: function (agent) {
|
||||||
return agent.bot.modes.getDocs();
|
return agent.bot.modes.getStr();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -124,4 +125,4 @@ export const queryList = [
|
||||||
return pad("Current code:\n`" + agent.coder.current_code +"`");
|
return pad("Current code:\n`" + agent.coder.current_code +"`");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
|
@ -1,47 +0,0 @@
|
||||||
export class Events {
|
|
||||||
constructor(agent, events) {
|
|
||||||
this.events = events;
|
|
||||||
if (agent != null)
|
|
||||||
this.init(agent, events);
|
|
||||||
}
|
|
||||||
|
|
||||||
init(agent, events) {
|
|
||||||
this.events = events;
|
|
||||||
for (let [event, callback, params] of events) {
|
|
||||||
if (callback != null)
|
|
||||||
agent.bot.on(event, this[callback].bind(this, agent, params));
|
|
||||||
}
|
|
||||||
|
|
||||||
agent.bot.on('time', () => {
|
|
||||||
if (agent.bot.time.timeOfDay == 0)
|
|
||||||
agent.bot.emit('sunrise');
|
|
||||||
else if (agent.bot.time.timeOfDay == 6000)
|
|
||||||
agent.bot.emit('noon');
|
|
||||||
else if (agent.bot.time.timeOfDay == 12000)
|
|
||||||
agent.bot.emit('sunset');
|
|
||||||
else if (agent.bot.time.timeOfDay == 18000)
|
|
||||||
agent.bot.emit('midnight');
|
|
||||||
});
|
|
||||||
|
|
||||||
agent.bot.on('health', () => {
|
|
||||||
if (agent.bot.health < 20)
|
|
||||||
agent.bot.emit('damaged');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async executeCode(agent, code) {
|
|
||||||
console.log('responding to event with code.');
|
|
||||||
agent.coder.queueCode(code);
|
|
||||||
let code_return = await agent.coder.execute();
|
|
||||||
console.log('code return:', code_return.message);
|
|
||||||
agent.history.add('system', code_return.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
sendThought(agent, message) {
|
|
||||||
agent.handleMessage(agent.name, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
sendChat(agent, message) {
|
|
||||||
agent.bot.chat(message);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { writeFileSync, readFileSync, mkdirSync } from 'fs';
|
import { writeFileSync, readFileSync, mkdirSync } from 'fs';
|
||||||
import { getCommandDocs } from './commands.js';
|
|
||||||
import { sendRequest } from '../utils/gpt.js';
|
|
||||||
import { stringifyTurns } from '../utils/text.js';
|
import { stringifyTurns } from '../utils/text.js';
|
||||||
|
import { sendRequest } from '../utils/gpt.js';
|
||||||
|
import { getCommandDocs } from './commands/index.js';
|
||||||
|
|
||||||
|
|
||||||
export class History {
|
export class History {
|
||||||
|
@ -14,9 +14,6 @@ export class History {
|
||||||
this.bio = '';
|
this.bio = '';
|
||||||
this.memory = '';
|
this.memory = '';
|
||||||
|
|
||||||
// The bot's events
|
|
||||||
this.events = [];
|
|
||||||
|
|
||||||
// Variables for controlling the agent's memory and knowledge
|
// Variables for controlling the agent's memory and knowledge
|
||||||
this.max_messages = 20;
|
this.max_messages = 20;
|
||||||
}
|
}
|
||||||
|
@ -91,7 +88,6 @@ export class History {
|
||||||
'name': this.name,
|
'name': this.name,
|
||||||
'bio': this.bio,
|
'bio': this.bio,
|
||||||
'memory': this.memory,
|
'memory': this.memory,
|
||||||
'events': this.events,
|
|
||||||
'turns': this.turns
|
'turns': this.turns
|
||||||
};
|
};
|
||||||
const json_data = JSON.stringify(data, null, 4);
|
const json_data = JSON.stringify(data, null, 4);
|
||||||
|
@ -111,7 +107,6 @@ export class History {
|
||||||
const obj = JSON.parse(data);
|
const obj = JSON.parse(data);
|
||||||
this.bio = obj.bio;
|
this.bio = obj.bio;
|
||||||
this.memory = obj.memory;
|
this.memory = obj.memory;
|
||||||
this.events = obj.events;
|
|
||||||
this.turns = obj.turns;
|
this.turns = obj.turns;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(`No file for profile '${load_path}' for agent ${this.name}.`);
|
console.error(`No file for profile '${load_path}' for agent ${this.name}.`);
|
||||||
|
|
|
@ -1,12 +1,6 @@
|
||||||
import * as skills from './skills.js';
|
import * as skills from './skills.js';
|
||||||
import * as world from './world.js';
|
import * as world from './world.js';
|
||||||
|
|
||||||
export function getSkillDocs() {
|
|
||||||
let docstring = "\n*SKILL DOCS\nThese skills are javascript functions that can be called when writing actions and skills.\n";
|
|
||||||
docstring += docHelper(Object.values(skills), 'skills');
|
|
||||||
docstring += docHelper(Object.values(world), 'world');
|
|
||||||
return docstring + '*\n';
|
|
||||||
}
|
|
||||||
|
|
||||||
export function docHelper(functions, module_name) {
|
export function docHelper(functions, module_name) {
|
||||||
let docstring = '';
|
let docstring = '';
|
||||||
|
@ -20,6 +14,9 @@ export function docHelper(functions, module_name) {
|
||||||
return docstring;
|
return docstring;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function containsCodeBlock(message) {
|
export function getSkillDocs() {
|
||||||
return message.indexOf('```') !== -1;
|
let docstring = "\n*SKILL DOCS\nThese skills are javascript functions that can be called when writing actions and skills.\n";
|
||||||
|
docstring += docHelper(Object.values(skills), 'skills');
|
||||||
|
docstring += docHelper(Object.values(world), 'world');
|
||||||
|
return docstring + '*\n';
|
||||||
}
|
}
|
|
@ -1,14 +1,39 @@
|
||||||
import { getItemId, getItemName } from "../utils/mcdata.js";
|
import * as mc from "../../utils/mcdata.js";
|
||||||
import { getNearestBlocks, getNearestBlock, getInventoryCounts, getNearestEntityWhere, getNearbyEntities, getNearbyBlocks } from "./world.js";
|
import * as world from "./world.js";
|
||||||
import pf from 'mineflayer-pathfinder';
|
import pf from 'mineflayer-pathfinder';
|
||||||
import Vec3 from 'vec3';
|
import Vec3 from 'vec3';
|
||||||
|
|
||||||
export function log(bot, message, chat=false) {
|
|
||||||
|
function log(bot, message, chat=false) {
|
||||||
bot.output += message + '\n';
|
bot.output += message + '\n';
|
||||||
if (chat)
|
if (chat)
|
||||||
bot.chat(message);
|
bot.chat(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function autoLight(bot) {
|
||||||
|
if (bot.modes.isOn('torch_placing') && !bot.interrupt_code) {
|
||||||
|
let nearest_torch = world.getNearestBlock(bot, 'torch', 8);
|
||||||
|
if (!nearest_torch) {
|
||||||
|
let has_torch = bot.inventory.items().find(item => item.name === 'torch');
|
||||||
|
if (has_torch) {
|
||||||
|
try {
|
||||||
|
log(bot, `Placing torch at ${bot.entity.position}.`);
|
||||||
|
await placeBlock(bot, 'torch', bot.entity.position.x, bot.entity.position.y, bot.entity.position.z);
|
||||||
|
return true;
|
||||||
|
} catch (err) {return true;}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function equipHighestAttack(bot) {
|
||||||
|
let weapons = bot.inventory.items().filter(item => item.name.includes('sword') || item.name.includes('axe') || item.name.includes('pickaxe') || item.name.includes('shovel'));
|
||||||
|
let weapon = weapons.sort((a, b) => b.attackDamage - a.attackDamage)[0];
|
||||||
|
if (weapon)
|
||||||
|
bot.equip(weapon, 'hand');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export async function craftRecipe(bot, itemName) {
|
export async function craftRecipe(bot, itemName) {
|
||||||
/**
|
/**
|
||||||
|
@ -19,15 +44,15 @@ export async function craftRecipe(bot, itemName) {
|
||||||
* @example
|
* @example
|
||||||
* await skills.craftRecipe(bot, "stick");
|
* await skills.craftRecipe(bot, "stick");
|
||||||
**/
|
**/
|
||||||
let recipes = bot.recipesFor(getItemId(itemName), null, 1, null); // get recipes that don't require a crafting table
|
let recipes = bot.recipesFor(mc.getItemId(itemName), null, 1, null); // get recipes that don't require a crafting table
|
||||||
let craftingTable = null;
|
let craftingTable = null;
|
||||||
if (!recipes || recipes.length === 0) {
|
if (!recipes || recipes.length === 0) {
|
||||||
craftingTable = getNearestBlock(bot, 'crafting_table', 6);
|
craftingTable = world.getNearestBlock(bot, 'crafting_table', 6);
|
||||||
if (craftingTable === null){
|
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.`)
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
recipes = bot.recipesFor(getItemId(itemName), null, 1, craftingTable);
|
recipes = bot.recipesFor(mc.getItemId(itemName), null, 1, craftingTable);
|
||||||
}
|
}
|
||||||
if (!recipes || recipes.length === 0) {
|
if (!recipes || recipes.length === 0) {
|
||||||
log(bot, `You do not have the resources to craft a ${itemName}.`);
|
log(bot, `You do not have the resources to craft a ${itemName}.`);
|
||||||
|
@ -37,7 +62,7 @@ export async function craftRecipe(bot, itemName) {
|
||||||
|
|
||||||
console.log('crafting...');
|
console.log('crafting...');
|
||||||
await bot.craft(recipe, 1, craftingTable);
|
await bot.craft(recipe, 1, craftingTable);
|
||||||
log(bot, `Successfully crafted ${itemName}, you now have ${getInventoryCounts(bot)[itemName]} ${itemName}.`);
|
log(bot, `Successfully crafted ${itemName}, you now have ${world.getInventoryCounts(bot)[itemName]} ${itemName}.`);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +85,7 @@ export async function smeltItem(bot, itemName, num=1) {
|
||||||
} // TODO: allow cobblestone, sand, clay, etc.
|
} // TODO: allow cobblestone, sand, clay, etc.
|
||||||
|
|
||||||
let furnaceBlock = undefined;
|
let furnaceBlock = undefined;
|
||||||
furnaceBlock = getNearestBlock(bot, 'furnace', 6);
|
furnaceBlock = world.getNearestBlock(bot, 'furnace', 6);
|
||||||
if (!furnaceBlock){
|
if (!furnaceBlock){
|
||||||
log(bot, `There is no furnace nearby.`)
|
log(bot, `There is no furnace nearby.`)
|
||||||
return false;
|
return false;
|
||||||
|
@ -71,14 +96,14 @@ export async function smeltItem(bot, itemName, num=1) {
|
||||||
const furnace = await bot.openFurnace(furnaceBlock);
|
const furnace = await bot.openFurnace(furnaceBlock);
|
||||||
// check if the furnace is already smelting something
|
// check if the furnace is already smelting something
|
||||||
let input_item = furnace.inputItem();
|
let input_item = furnace.inputItem();
|
||||||
if (input_item && input_item.type !== getItemId(itemName) && input_item.count > 0) {
|
if (input_item && input_item.type !== mc.getItemId(itemName) && input_item.count > 0) {
|
||||||
// TODO: check if furnace is currently burning fuel. furnace.fuel is always null, I think there is a bug.
|
// TODO: check if furnace is currently burning fuel. furnace.fuel is always null, I think there is a bug.
|
||||||
// This only checks if the furnace has an input item, but it may not be smelting it and should be cleared.
|
// This only checks if the furnace has an input item, but it may not be smelting it and should be cleared.
|
||||||
log(bot, `The furnace is currently smelting ${getItemName(input_item.type)}.`);
|
log(bot, `The furnace is currently smelting ${mc.getItemName(input_item.type)}.`);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// check if the bot has enough items to smelt
|
// check if the bot has enough items to smelt
|
||||||
let inv_counts = getInventoryCounts(bot);
|
let inv_counts = world.getInventoryCounts(bot);
|
||||||
if (!inv_counts[itemName] || inv_counts[itemName] < num) {
|
if (!inv_counts[itemName] || inv_counts[itemName] < num) {
|
||||||
log(bot, `You do not have enough ${itemName} to smelt.`);
|
log(bot, `You do not have enough ${itemName} to smelt.`);
|
||||||
return false;
|
return false;
|
||||||
|
@ -93,11 +118,11 @@ export async function smeltItem(bot, itemName, num=1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
await furnace.putFuel(fuel.type, null, put_fuel);
|
await furnace.putFuel(fuel.type, null, put_fuel);
|
||||||
log(bot, `Added ${put_fuel} ${getItemName(fuel.type)} to furnace fuel.`);
|
log(bot, `Added ${put_fuel} ${mc.getItemName(fuel.type)} to furnace fuel.`);
|
||||||
console.log(`Added ${put_fuel} ${getItemName(fuel.type)} to furnace fuel.`)
|
console.log(`Added ${put_fuel} ${mc.getItemName(fuel.type)} to furnace fuel.`)
|
||||||
}
|
}
|
||||||
// put the items in the furnace
|
// put the items in the furnace
|
||||||
await furnace.putInput(getItemId(itemName), null, num);
|
await furnace.putInput(mc.getItemId(itemName), null, num);
|
||||||
// wait for the items to smelt
|
// wait for the items to smelt
|
||||||
let total = 0;
|
let total = 0;
|
||||||
let collected_last = true;
|
let collected_last = true;
|
||||||
|
@ -128,10 +153,10 @@ export async function smeltItem(bot, itemName, num=1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (total < num) {
|
if (total < num) {
|
||||||
log(bot, `Only smelted ${total} ${getItemName(smelted_item.type)}.`);
|
log(bot, `Only smelted ${total} ${mc.getItemName(smelted_item.type)}.`);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
log(bot, `Successfully smelted ${itemName}, got ${total} ${getItemName(smelted_item.type)}.`);
|
log(bot, `Successfully smelted ${itemName}, got ${total} ${mc.getItemName(smelted_item.type)}.`);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,7 +168,7 @@ export async function clearNearestFurnace(bot) {
|
||||||
* @example
|
* @example
|
||||||
* await skills.clearNearestFurnace(bot);
|
* await skills.clearNearestFurnace(bot);
|
||||||
**/
|
**/
|
||||||
let furnaceBlock = getNearestBlock(bot, 'furnace', 6);
|
let furnaceBlock = world.getNearestBlock(bot, 'furnace', 6);
|
||||||
if (!furnaceBlock){
|
if (!furnaceBlock){
|
||||||
log(bot, `There is no furnace nearby.`)
|
log(bot, `There is no furnace nearby.`)
|
||||||
return false;
|
return false;
|
||||||
|
@ -170,14 +195,6 @@ export async function clearNearestFurnace(bot) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function equipHighestAttack(bot) {
|
|
||||||
let weapons = bot.inventory.items().filter(item => item.name.includes('sword') || item.name.includes('axe') || item.name.includes('pickaxe') || item.name.includes('shovel'));
|
|
||||||
let weapon = weapons.sort((a, b) => b.attackDamage - a.attackDamage)[0];
|
|
||||||
if (weapon)
|
|
||||||
bot.equip(weapon, 'hand');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export async function attackNearest(bot, mobType, kill=true) {
|
export async function attackNearest(bot, mobType, kill=true) {
|
||||||
/**
|
/**
|
||||||
* Attack mob of the given type.
|
* Attack mob of the given type.
|
||||||
|
@ -221,7 +238,7 @@ export async function attackEntity(bot, entity, kill=true) {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
bot.pvp.attack(entity);
|
bot.pvp.attack(entity);
|
||||||
while (getNearbyEntities(bot, 16).includes(entity)) {
|
while (world.getNearbyEntities(bot, 16).includes(entity)) {
|
||||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||||
if (bot.interrupt_code) {
|
if (bot.interrupt_code) {
|
||||||
bot.pvp.stop();
|
bot.pvp.stop();
|
||||||
|
@ -245,7 +262,7 @@ export async function defendSelf(bot, range=8) {
|
||||||
* **/
|
* **/
|
||||||
bot.modes.pause('self_defense');
|
bot.modes.pause('self_defense');
|
||||||
let attacked = false;
|
let attacked = false;
|
||||||
let enemy = getNearestEntityWhere(bot, entity => isHostile(entity), range);
|
let enemy = world.getNearestEntityWhere(bot, entity => mc.isHostile(entity), range);
|
||||||
while (enemy) {
|
while (enemy) {
|
||||||
equipHighestAttack(bot);
|
equipHighestAttack(bot);
|
||||||
if (bot.entity.position.distanceTo(enemy.position) > 4 && enemy.name !== 'creeper' && enemy.name !== 'phantom') {
|
if (bot.entity.position.distanceTo(enemy.position) > 4 && enemy.name !== 'creeper' && enemy.name !== 'phantom') {
|
||||||
|
@ -257,7 +274,7 @@ export async function defendSelf(bot, range=8) {
|
||||||
bot.pvp.attack(enemy);
|
bot.pvp.attack(enemy);
|
||||||
attacked = true;
|
attacked = true;
|
||||||
await new Promise(resolve => setTimeout(resolve, 500));
|
await new Promise(resolve => setTimeout(resolve, 500));
|
||||||
enemy = getNearestEntityWhere(bot, entity => isHostile(entity), range);
|
enemy = world.getNearestEntityWhere(bot, entity => mc.isHostile(entity), range);
|
||||||
if (bot.interrupt_code) {
|
if (bot.interrupt_code) {
|
||||||
bot.pvp.stop();
|
bot.pvp.stop();
|
||||||
return false;
|
return false;
|
||||||
|
@ -288,7 +305,7 @@ export async function collectBlock(bot, blockType, num=1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let collected = 0;
|
let collected = 0;
|
||||||
const blocks = getNearestBlocks(bot, blockType, 64, num);
|
const blocks = world.getNearestBlocks(bot, blockType, 64, num);
|
||||||
if (blocks.length === 0) {
|
if (blocks.length === 0) {
|
||||||
log(bot, `Could not find any ${blockType} to collect.`);
|
log(bot, `Could not find any ${blockType} to collect.`);
|
||||||
return false;
|
return false;
|
||||||
|
@ -553,7 +570,7 @@ export async function goToPosition(bot, x, y, z, min_distance=2) {
|
||||||
* @param {number} distance, the distance to keep from the position. Defaults to 2.
|
* @param {number} distance, the distance to keep from the position. Defaults to 2.
|
||||||
* @returns {Promise<boolean>} true if the position was reached, false otherwise.
|
* @returns {Promise<boolean>} true if the position was reached, false otherwise.
|
||||||
* @example
|
* @example
|
||||||
* let position = world.getNearestBlock(bot, "oak_log", 64).position;
|
* let position = world.world.getNearestBlock(bot, "oak_log", 64).position;
|
||||||
* await skills.goToPosition(bot, position.x, position.y, position.x + 20);
|
* await skills.goToPosition(bot, position.x, position.y, position.x + 20);
|
||||||
**/
|
**/
|
||||||
if (x == null || y == null || z == null) {
|
if (x == null || y == null || z == null) {
|
||||||
|
@ -616,7 +633,7 @@ export async function followPlayer(bot, username) {
|
||||||
while (!bot.interrupt_code) {
|
while (!bot.interrupt_code) {
|
||||||
let acted = false;
|
let acted = false;
|
||||||
if (bot.modes.isOn('self_defense')) {
|
if (bot.modes.isOn('self_defense')) {
|
||||||
const enemy = getNearestEntityWhere(bot, entity => isHostile(entity), attack_distance);
|
const enemy = world.getNearestEntityWhere(bot, entity => mc.isHostile(entity), attack_distance);
|
||||||
if (enemy) {
|
if (enemy) {
|
||||||
log(bot, `Found ${enemy.name}, attacking!`, true);
|
log(bot, `Found ${enemy.name}, attacking!`, true);
|
||||||
await defendSelf(bot, 8);
|
await defendSelf(bot, 8);
|
||||||
|
@ -624,7 +641,7 @@ export async function followPlayer(bot, username) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (bot.modes.isOn('hunting')) {
|
if (bot.modes.isOn('hunting')) {
|
||||||
const animal = getNearestEntityWhere(bot, entity => isHuntable(entity), attack_distance);
|
const animal = world.getNearestEntityWhere(bot, entity => mc.isHuntable(entity), attack_distance);
|
||||||
if (animal) {
|
if (animal) {
|
||||||
log(bot, `Hunting ${animal.name}!`, true);
|
log(bot, `Hunting ${animal.name}!`, true);
|
||||||
await attackEntity(bot, animal, true);
|
await attackEntity(bot, animal, true);
|
||||||
|
@ -676,34 +693,3 @@ export async function goToBed(bot) {
|
||||||
log(bot, `You have woken up.`);
|
log(bot, `You have woken up.`);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function isHuntable(mob) {
|
|
||||||
if (!mob || !mob.name) return false;
|
|
||||||
const animals = ['chicken', 'cod', 'cow', 'llama', 'mooshroom', 'pig', 'pufferfish', 'rabbit', 'salmon', 'sheep', 'squid', 'tropical_fish', 'turtle'];
|
|
||||||
return animals.includes(mob.name.toLowerCase()) && !mob.metadata[16]; // metadata 16 is not baby
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export function isHostile(mob) {
|
|
||||||
if (!mob || !mob.name) return false;
|
|
||||||
return (mob.type === 'mob' || mob.type === 'hostile') && mob.name !== 'iron_golem' && mob.name !== 'snow_golem';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
async function autoLight(bot) {
|
|
||||||
if (bot.modes.isOn('torch_placing') && !bot.interrupt_code) {
|
|
||||||
let nearest_torch = getNearestBlock(bot, 'torch', 8);
|
|
||||||
if (!nearest_torch) {
|
|
||||||
let has_torch = bot.inventory.items().find(item => item.name === 'torch');
|
|
||||||
if (has_torch) {
|
|
||||||
try {
|
|
||||||
log(bot, `Placing torch at ${bot.entity.position}.`);
|
|
||||||
await placeBlock(bot, 'torch', bot.entity.position.x, bot.entity.position.y, bot.entity.position.z);
|
|
||||||
return true;
|
|
||||||
} catch (err) {return true;}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { getAllBlockIds } from '../utils/mcdata.js';
|
import { getAllBlockIds } from '../../utils/mcdata.js';
|
||||||
|
|
||||||
|
|
||||||
export function getNearestBlocks(bot, block_types, distance=16, count=1) {
|
export function getNearestBlocks(bot, block_types, distance=16, count=1) {
|
||||||
|
@ -206,3 +206,16 @@ export function getNearbyBlockTypes(bot, distance=16) {
|
||||||
}
|
}
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function getBiomeName(bot) {
|
||||||
|
/**
|
||||||
|
* Get the name of the biome the bot is in.
|
||||||
|
* @param {Bot} bot - The bot to get the biome for.
|
||||||
|
* @returns {string} - The name of the biome.
|
||||||
|
* @example
|
||||||
|
* let biome = world.getBiomeName(bot);
|
||||||
|
**/
|
||||||
|
const biomeId = bot.world.getBiome(bot.entity.position);
|
||||||
|
return mcdata.biomes[biomeId].name;
|
||||||
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
import * as skills from './skills.js';
|
import * as skills from './library/skills.js';
|
||||||
import * as world from './world.js';
|
import * as world from './library/world.js';
|
||||||
|
import * as mc from '../utils/mcdata.js';
|
||||||
|
|
||||||
|
|
||||||
// a mode is a function that is called every tick to respond immediately to the world
|
// a mode is a function that is called every tick to respond immediately to the world
|
||||||
// it has the following fields:
|
// it has the following fields:
|
||||||
|
@ -17,7 +19,7 @@ const modes = [
|
||||||
active: false,
|
active: false,
|
||||||
update: function (agent) {
|
update: function (agent) {
|
||||||
if (this.active) return;
|
if (this.active) return;
|
||||||
const enemy = world.getNearestEntityWhere(agent.bot, entity => skills.isHostile(entity), 8);
|
const enemy = world.getNearestEntityWhere(agent.bot, entity => mc.isHostile(entity), 8);
|
||||||
if (enemy) {
|
if (enemy) {
|
||||||
agent.bot.chat(`Fighting ${enemy.name}!`);
|
agent.bot.chat(`Fighting ${enemy.name}!`);
|
||||||
execute(this, agent, async () => {
|
execute(this, agent, async () => {
|
||||||
|
@ -33,7 +35,7 @@ const modes = [
|
||||||
active: false,
|
active: false,
|
||||||
update: function (agent) {
|
update: function (agent) {
|
||||||
if (agent.idle) {
|
if (agent.idle) {
|
||||||
const huntable = world.getNearestEntityWhere(agent.bot, entity => skills.isHuntable(entity), 8);
|
const huntable = world.getNearestEntityWhere(agent.bot, entity => mc.isHuntable(entity), 8);
|
||||||
if (huntable) {
|
if (huntable) {
|
||||||
execute(this, agent, async () => {
|
execute(this, agent, async () => {
|
||||||
agent.bot.chat(`Hunting ${huntable.name}!`);
|
agent.bot.chat(`Hunting ${huntable.name}!`);
|
||||||
|
@ -165,7 +167,7 @@ class ModeController {
|
||||||
this.modes_map[mode_name].paused = true;
|
this.modes_map[mode_name].paused = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
getDocs() {
|
getStr() {
|
||||||
let res = 'Available Modes:';
|
let res = 'Available Modes:';
|
||||||
for (let mode of this.modes_list) {
|
for (let mode of this.modes_list) {
|
||||||
let on = mode.on ? 'ON' : 'OFF';
|
let on = mode.on ? 'ON' : 'OFF';
|
||||||
|
@ -197,4 +199,4 @@ class ModeController {
|
||||||
export function initModes(agent) {
|
export function initModes(agent) {
|
||||||
// the mode controller is added to the bot object so it is accessible from anywhere the bot is used
|
// the mode controller is added to the bot object so it is accessible from anywhere the bot is used
|
||||||
agent.bot.modes = new ModeController(agent);
|
agent.bot.modes = new ModeController(agent);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { readFileSync } from 'fs';
|
import { readFileSync } from 'fs';
|
||||||
import { embed, cosineSimilarity } from '../utils/gpt.js';
|
import { embed, cosineSimilarity } from './gpt.js';
|
||||||
import { stringifyTurns } from '../utils/text.js';
|
import { stringifyTurns } from './text.js';
|
||||||
|
|
||||||
|
|
||||||
export class Examples {
|
export class Examples {
|
|
@ -33,6 +33,17 @@ export function initBot(username) {
|
||||||
return bot;
|
return bot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isHuntable(mob) {
|
||||||
|
if (!mob || !mob.name) return false;
|
||||||
|
const animals = ['chicken', 'cod', 'cow', 'llama', 'mooshroom', 'pig', 'pufferfish', 'rabbit', 'salmon', 'sheep', 'squid', 'tropical_fish', 'turtle'];
|
||||||
|
return animals.includes(mob.name.toLowerCase()) && !mob.metadata[16]; // metadata 16 is not baby
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isHostile(mob) {
|
||||||
|
if (!mob || !mob.name) return false;
|
||||||
|
return (mob.type === 'mob' || mob.type === 'hostile') && mob.name !== 'iron_golem' && mob.name !== 'snow_golem';
|
||||||
|
}
|
||||||
|
|
||||||
export function getItemId(item) {
|
export function getItemId(item) {
|
||||||
return mcdata.itemsByName[item].id;
|
return mcdata.itemsByName[item].id;
|
||||||
}
|
}
|
||||||
|
@ -55,7 +66,6 @@ export function getAllItems(ignore) {
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function getAllItemIds(ignore) {
|
export function getAllItemIds(ignore) {
|
||||||
const items = getAllItems(ignore);
|
const items = getAllItems(ignore);
|
||||||
let itemIds = [];
|
let itemIds = [];
|
||||||
|
@ -65,7 +75,6 @@ export function getAllItemIds(ignore) {
|
||||||
return itemIds;
|
return itemIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function getAllBlocks(ignore) {
|
export function getAllBlocks(ignore) {
|
||||||
if (!ignore) {
|
if (!ignore) {
|
||||||
ignore = [];
|
ignore = [];
|
||||||
|
@ -80,7 +89,6 @@ export function getAllBlocks(ignore) {
|
||||||
return blocks;
|
return blocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function getAllBlockIds(ignore) {
|
export function getAllBlockIds(ignore) {
|
||||||
const blocks = getAllBlocks(ignore);
|
const blocks = getAllBlocks(ignore);
|
||||||
let blockIds = [];
|
let blockIds = [];
|
||||||
|
@ -89,8 +97,3 @@ export function getAllBlockIds(ignore) {
|
||||||
}
|
}
|
||||||
return blockIds;
|
return blockIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getBiomeName(bot) {
|
|
||||||
const biomeId = bot.world.getBiome(bot.entity.position);
|
|
||||||
return mcdata.biomes[biomeId].name;
|
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue