mirror of
https://github.com/kolbytn/mindcraft.git
synced 2025-04-23 14:42:07 +02:00
commit
f3ff79b664
15 changed files with 466 additions and 434 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -2,3 +2,6 @@
|
||||||
node_modules/
|
node_modules/
|
||||||
package-lock.json
|
package-lock.json
|
||||||
temp.js
|
temp.js
|
||||||
|
scratch.js
|
||||||
|
agent_code/**
|
||||||
|
!agent_code/template.js
|
134
act.js
134
act.js
|
@ -1,134 +0,0 @@
|
||||||
import { writeFileSync } from 'fs';
|
|
||||||
|
|
||||||
import { getDetailedSkills, getWorldFunctions } from './utils/context.js';
|
|
||||||
import { sendRequest } from './utils/gpt.js';
|
|
||||||
|
|
||||||
|
|
||||||
function buildSystemMessage(bot) {
|
|
||||||
let message = 'You are a helpful Minecraft bot. Given the dialogue, reflect on what you are doing and generate javascript code to accomplish that goal. Use only functions listed below to write your code.';
|
|
||||||
message += "\n\n" + getDetailedSkills();
|
|
||||||
message += "\n\n" + getWorldFunctions();
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function buildExamples() {
|
|
||||||
return [
|
|
||||||
`mr_steve2: Will you help me collect wood?
|
|
||||||
|
|
||||||
!blocks
|
|
||||||
\`\`\`
|
|
||||||
NEARBY_BLOCKS
|
|
||||||
- oak_log
|
|
||||||
- dirt
|
|
||||||
- cobblestone
|
|
||||||
\`\`\`
|
|
||||||
|
|
||||||
Me: I'd be glad to help you collect wood.`,
|
|
||||||
`I'm going to help mr_steve2 collect wood. The type of wood block nearby is 'oak_log'. I'll adjust my code to collect an 'oak_log' for mr_steve2.
|
|
||||||
\`\`\`
|
|
||||||
await skills.collectBlock(bot, 'oak_log');
|
|
||||||
await skills.giveToPlayer(bot, 'oak_log', 'mr_steve2');
|
|
||||||
\`\`\``,
|
|
||||||
`sally32: What are you doing?
|
|
||||||
|
|
||||||
!action
|
|
||||||
\`\`\`
|
|
||||||
await skills.equipItem(bot, 'wooden_pickaxe');
|
|
||||||
while (world.getInventory(bot).coal_ore < 10) {
|
|
||||||
await skills.collectBlock(bot, 'coal_ore');
|
|
||||||
}
|
|
||||||
\`\`\`
|
|
||||||
|
|
||||||
Me: I'm looking for coal. Have you seen any?
|
|
||||||
|
|
||||||
sally32: Yes, there's some in this cave, follow me.`,
|
|
||||||
`I'm going to follow sally32 to the cave and collect coal. I'll adjust my code to follow sally32 until I find coal_ore and then I'll mine it.
|
|
||||||
\`\`\`
|
|
||||||
while (true) {
|
|
||||||
await skills.goToPlayer(bot, 'sally32');
|
|
||||||
if (world.getNearbyBlocks(bot).includes('coal_ore')) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await skills.equipItem(bot, 'wooden_pickaxe');
|
|
||||||
while (world.getInventory(bot).coal_ore < 10) {
|
|
||||||
await skills.collectBlock(bot, 'coal_ore');
|
|
||||||
}
|
|
||||||
\`\`\``,
|
|
||||||
`user42: come here
|
|
||||||
|
|
||||||
Me: Sure! I'm on my way.`,
|
|
||||||
`I'm going to navigate to user42.
|
|
||||||
\`\`\`
|
|
||||||
await skills.goToPlayer(bot, 'user42');
|
|
||||||
\`\`\``,
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export var currentCode = '';
|
|
||||||
|
|
||||||
|
|
||||||
export async function executeCode(bot) {
|
|
||||||
let src = "import * as skills from './utils/skills.js';";
|
|
||||||
src += "\nimport * as world from './utils/world.js';"
|
|
||||||
src += `\n\nexport async function main(bot) {\n`;
|
|
||||||
for (let line of currentCode.split('\n')) {
|
|
||||||
src += ` ${line}\n`;
|
|
||||||
}
|
|
||||||
src += `}\n`;
|
|
||||||
|
|
||||||
writeFileSync('./temp.js', src, (err) => {
|
|
||||||
if (err) throw err;
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('executing code...\n' + currentCode);
|
|
||||||
try {
|
|
||||||
await (await import('./temp.js')).main(bot);
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err);
|
|
||||||
currentCode = '';
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
currentCode = '';
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export async function writeCode(bot, username, messages) {
|
|
||||||
let turns = buildExamples();
|
|
||||||
|
|
||||||
// For now, get rid of the first 6 example messages
|
|
||||||
messages = messages.slice(6);
|
|
||||||
|
|
||||||
let startIndex = messages.length - 6;
|
|
||||||
if (startIndex < 0)
|
|
||||||
startIndex = 0;
|
|
||||||
|
|
||||||
turns.push('');
|
|
||||||
for (let i = startIndex; i < messages.length; i++) {
|
|
||||||
if (i % 2 == 0 && messages[i] != '') {
|
|
||||||
turns[turns.length - 1] += `\n\n${username}: ${messages[i]}`;
|
|
||||||
} else if (messages[i] != '') {
|
|
||||||
turns[turns.length - 1] += `\n\nMe: ${messages[i]}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
turns[turns.length - 1] = turns[turns.length - 1].trim();
|
|
||||||
let systemMessage = buildSystemMessage(bot);
|
|
||||||
let actResponse = await sendRequest(turns, systemMessage);
|
|
||||||
console.log(actResponse);
|
|
||||||
|
|
||||||
let code = actResponse.split('\`\`\`');
|
|
||||||
if (code.length <= 1)
|
|
||||||
return code;
|
|
||||||
if (!code[1].trim())
|
|
||||||
return code;
|
|
||||||
|
|
||||||
currentCode = code[1].trim();
|
|
||||||
if (currentCode.slice(0, 10) == 'javascript')
|
|
||||||
currentCode = currentCode.slice(10).trim();
|
|
||||||
|
|
||||||
return currentCode;
|
|
||||||
}
|
|
76
agent.js
Normal file
76
agent.js
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
import { initBot } from './utils/mcdata.js';
|
||||||
|
import { sendRequest } from './utils/gpt.js';
|
||||||
|
import { History } from './utils/history.js';
|
||||||
|
import { Coder } from './utils/coder.js';
|
||||||
|
import { getQuery, containsQuery, getQueryDocs } from './utils/queries.js';
|
||||||
|
import { getSkillDocs, containsCodeBlock } from './utils/skill_library.js';
|
||||||
|
|
||||||
|
|
||||||
|
export class Agent {
|
||||||
|
constructor(name) {
|
||||||
|
this.name = name;
|
||||||
|
|
||||||
|
this.system_message = `You are a playful Minecraft bot named '${name}' that can communicate with players, see, move, mine, build, and interact with the world by writing and executing code.
|
||||||
|
Act human-like as if you were a typical Minecraft player, rather than an AI. Be brief in your responses, omit needless words, and do not give instructions unless asked.`;
|
||||||
|
this.system_message += getQueryDocs();
|
||||||
|
this.system_message += getSkillDocs();
|
||||||
|
|
||||||
|
this.bot = initBot(name);
|
||||||
|
this.history = new History(this);
|
||||||
|
this.coder = new Coder(this);
|
||||||
|
|
||||||
|
this.bot.on('login', () => {
|
||||||
|
this.bot.chat('Hello world! I am ' + this.name);
|
||||||
|
console.log(`${this.name} logged in.`);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.bot.on('chat', (username, message) => {
|
||||||
|
if (username === this.name) return;
|
||||||
|
console.log('received message from', username, ':', message);
|
||||||
|
|
||||||
|
this.respond(username, message);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async respond(username, message) {
|
||||||
|
this.history.add(username, message);
|
||||||
|
for (let i=0; i<5; i++) {
|
||||||
|
let res = await sendRequest(this.history.getHistory(), this.system_message);
|
||||||
|
this.history.add(this.name, res);
|
||||||
|
let query_cmd = containsQuery(res);
|
||||||
|
if (query_cmd) { // contains query
|
||||||
|
let message = res.substring(0, res.indexOf(query_cmd)).trim();
|
||||||
|
if (message)
|
||||||
|
this.bot.chat(message);
|
||||||
|
console.log('Agent used query:', query_cmd);
|
||||||
|
let query = getQuery(query_cmd);
|
||||||
|
let query_res = query.perform(this);
|
||||||
|
this.history.add(this.name, query_res);
|
||||||
|
}
|
||||||
|
else if (containsCodeBlock(res)) { // contains code block
|
||||||
|
let message = res.substring(0, res.indexOf('```')).trim();
|
||||||
|
if (message)
|
||||||
|
this.bot.chat(message);
|
||||||
|
else
|
||||||
|
this.bot.chat("Executing code...");
|
||||||
|
let code = res.substring(res.indexOf('```')+3, res.lastIndexOf('```'));
|
||||||
|
if (code) {
|
||||||
|
console.log('Queuing code: ' + code);
|
||||||
|
this.coder.queueCode(code);
|
||||||
|
let code_return = await this.coder.execute();
|
||||||
|
if (code_return.success)
|
||||||
|
break;
|
||||||
|
else {
|
||||||
|
let message = "Code execution failed: " + code_return.message;
|
||||||
|
message += "\n Write code to fix the problem and try again.";
|
||||||
|
this.history.add(this.name, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { // conversation response
|
||||||
|
this.bot.chat(res);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
6
agent_code/template.js
Normal file
6
agent_code/template.js
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
import * as skills from '../utils/skills.js';
|
||||||
|
import * as world from '../utils/world.js';
|
||||||
|
// this file is currently unused
|
||||||
|
export async function main(bot) {
|
||||||
|
// agent's code goes here
|
||||||
|
}
|
81
chat.js
81
chat.js
|
@ -1,81 +0,0 @@
|
||||||
import { sendRequest } from './utils/gpt.js';
|
|
||||||
import { getHistory, addEvent } from './utils/history.js';
|
|
||||||
import { getStats, getInventory, getBlocks, getNearbyEntities, getCraftable, getDetailedSkills, getWorldFunctions } from './utils/context.js';
|
|
||||||
import { currentCode, writeCode } from './act.js';
|
|
||||||
|
|
||||||
|
|
||||||
function buildSystemMessage() {
|
|
||||||
let message = 'You are a playful Minecraft bot that can communicate with players and move within and interact with the world.';
|
|
||||||
message += ' Act human-like as if you were a typical Minecraft player, rather than an AI.';
|
|
||||||
message += ' Do not give instructions unless asked, and always be brief in your responses.';
|
|
||||||
message += '\n\nYou can use the following commands followed by to query for information about the world.';
|
|
||||||
message += ' The query response will be returned between sets of \`\`\`:';
|
|
||||||
message += '\n!stats - get player and world stats (current health, time of day, etc.)';
|
|
||||||
message += '\n!inventory - get your current inventory';
|
|
||||||
message += '\n!blocks - get a list of nearby blocks';
|
|
||||||
message += '\n!craftable - get a list of craftable items with your current inventory';
|
|
||||||
message += '\n!entities - get a list of nearby players and entities';
|
|
||||||
message += '\n!action - get the currently executing code';
|
|
||||||
message += '\n\nYou can also execute actions such as moving and mining in Minecraft by writing javascript code.';
|
|
||||||
message += ' To do so, simply begin a codeblock with the "!execute" command. For example:';
|
|
||||||
message += '\n!execute\n\`\`\`\nCODE\n\`\`\`';
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export async function getChatResponse(bot, user, message) {
|
|
||||||
addEvent(user, message);
|
|
||||||
let turns = getHistory(user);
|
|
||||||
let systemMessage = buildSystemMessage();
|
|
||||||
|
|
||||||
let lastResponse = '';
|
|
||||||
let botResponse = '';
|
|
||||||
let botEvent = '';
|
|
||||||
let res = null;
|
|
||||||
for (let i = 0; i < 5; i++) {
|
|
||||||
|
|
||||||
res = await sendRequest(turns, systemMessage, '\`\`\`');
|
|
||||||
console.log('received chat:', res);
|
|
||||||
|
|
||||||
res = '\n' + res.trim();
|
|
||||||
lastResponse = '';
|
|
||||||
if (!res.includes('\n!')) {
|
|
||||||
botResponse += res;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
while (!res.startsWith('\n!')) {
|
|
||||||
lastResponse += res.slice(0, 1);
|
|
||||||
res = res.slice(1, res.length);
|
|
||||||
}
|
|
||||||
botResponse += '\n' + lastResponse.trim();
|
|
||||||
res = res.trim();
|
|
||||||
|
|
||||||
let queryRes = null;
|
|
||||||
if (res.startsWith('!stats')) {
|
|
||||||
queryRes = '\n\n!stats\n\`\`\`\n' + getStats(bot) + '\n\`\`\`';
|
|
||||||
} else if (res.startsWith('!inventory')) {
|
|
||||||
queryRes = '\n\n!inventory\n\`\`\`\n' + getInventory(bot) + '\n\`\`\`';
|
|
||||||
} else if (res.startsWith('!blocks')) {
|
|
||||||
queryRes = '\n\n!blocks\n\`\`\`\n' + getBlocks(bot) + '\n\`\`\`';
|
|
||||||
} else if (res.startsWith('!craftable')) {
|
|
||||||
queryRes = '\n\n!craftable\n\`\`\`\n' + getCraftable(bot) + '\n\`\`\`';
|
|
||||||
} else if (res.startsWith('!entities')) {
|
|
||||||
queryRes = '\n\n!entities\n\`\`\`\n' + getNearbyEntities(bot) + '\n\`\`\`';
|
|
||||||
} else if (res.startsWith('!action')) {
|
|
||||||
queryRes = '\n\n!action\n\`\`\`\n' + currentCode + '\n\`\`\`';
|
|
||||||
} else if (res.startsWith('!execute')) {
|
|
||||||
queryRes = '\n\n!execute\n\`\`\`\n' + await writeCode(bot, user, turns.concat(lastResponse.trim())) + '\n\`\`\`';
|
|
||||||
botEvent += lastResponse + queryRes + '\n\n';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('query response:', queryRes);
|
|
||||||
botEvent += lastResponse + queryRes + '\n\n';
|
|
||||||
turns.push(lastResponse + queryRes);
|
|
||||||
turns.push('');
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('sending chat:', botResponse.trim());
|
|
||||||
addEvent('bot', botEvent.trim());
|
|
||||||
return botResponse.trim();
|
|
||||||
}
|
|
35
main.js
35
main.js
|
@ -1,34 +1,3 @@
|
||||||
import { createBot } from 'mineflayer';
|
import { Agent } from './agent.js';
|
||||||
import { pathfinder } from 'mineflayer-pathfinder';
|
|
||||||
import { plugin } from 'mineflayer-collectblock';
|
|
||||||
|
|
||||||
import { getChatResponse } from './chat.js';
|
new Agent('andy');
|
||||||
import { executeCode } from './act.js';
|
|
||||||
|
|
||||||
|
|
||||||
async function handleMessage(username, message) {
|
|
||||||
if (username === bot.username) return;
|
|
||||||
console.log('received message from', username, ':', message);
|
|
||||||
|
|
||||||
let chat = await getChatResponse(bot, username, message);
|
|
||||||
bot.chat(chat);
|
|
||||||
|
|
||||||
let actResult = await executeCode(bot);
|
|
||||||
if (actResult) {
|
|
||||||
console.log('completed action');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const bot = createBot({
|
|
||||||
host: '127.0.0.1',
|
|
||||||
port: 55916,
|
|
||||||
username: 'andi'
|
|
||||||
})
|
|
||||||
bot.loadPlugin(pathfinder)
|
|
||||||
bot.loadPlugin(plugin)
|
|
||||||
|
|
||||||
console.log('bot created')
|
|
||||||
|
|
||||||
bot.on('chat', handleMessage);
|
|
||||||
bot.on('whisper', handleMessage);
|
|
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"minecraft-data": "^3.46.2",
|
||||||
"mineflayer": "^4.14.0",
|
"mineflayer": "^4.14.0",
|
||||||
"mineflayer-collectblock": "^1.4.1",
|
"mineflayer-collectblock": "^1.4.1",
|
||||||
"mineflayer-pathfinder": "^2.4.4",
|
"mineflayer-pathfinder": "^2.4.4",
|
||||||
|
|
80
utils/coder.js
Normal file
80
utils/coder.js
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
import { writeFile, unlink } from 'fs';
|
||||||
|
|
||||||
|
export class Coder {
|
||||||
|
constructor(agent) {
|
||||||
|
this.agent = agent;
|
||||||
|
this.current_code = '';
|
||||||
|
this.file_counter = 0;
|
||||||
|
this.fp = './agent_code/';
|
||||||
|
}
|
||||||
|
|
||||||
|
queueCode(code) {
|
||||||
|
if (code.startsWith('javascript'))
|
||||||
|
code = code.slice(10);
|
||||||
|
this.current_code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasCode() {
|
||||||
|
return this.current_code.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeFilePromise(filename, src) {
|
||||||
|
// makes it so we can await this function
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
writeFile(filename, src, (err) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err);
|
||||||
|
} else {
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async execute() {
|
||||||
|
if (!this.current_code) return {success: false, message: "No code to execute."};
|
||||||
|
let src = "import * as skills from '../utils/skills.js';";
|
||||||
|
src += "\nimport * as world from '../utils/world.js';"
|
||||||
|
src += `\n\nexport async function main(bot) {\n`;
|
||||||
|
for (let line of this.current_code.split('\n')) {
|
||||||
|
src += ` ${line}\n`;
|
||||||
|
}
|
||||||
|
src += ` return true;\n}\n`; // potentially redundant return statement, in case agent doesn't return anything
|
||||||
|
|
||||||
|
console.log("writing to file...", src)
|
||||||
|
|
||||||
|
let filename = this.fp + this.file_counter + '.js';
|
||||||
|
if (this.file_counter > 0) {
|
||||||
|
let prev_filename = this.fp + (this.file_counter-1) + '.js';
|
||||||
|
unlink(prev_filename, (err) => {
|
||||||
|
console.log("deleted file " + prev_filename);
|
||||||
|
if (err) console.error(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.file_counter++;
|
||||||
|
|
||||||
|
let result = await this.writeFilePromise(filename, src);
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
console.error('Error writing code execution file: ' + result);
|
||||||
|
return {success: false, message: result};
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
console.log('executing code...\n');
|
||||||
|
let execution_file = await import('.'+filename);
|
||||||
|
this.clear();
|
||||||
|
let success = await execution_file.main(this.agent.bot);
|
||||||
|
return {success, message: ""};
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Problem executing code:" + err);
|
||||||
|
this.clear();
|
||||||
|
return {success: false, message: err};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clear() {
|
||||||
|
this.current_code = '';
|
||||||
|
this.agent.bot.pathfinder.setGoal(null);
|
||||||
|
}
|
||||||
|
}
|
15
utils/gpt.js
15
utils/gpt.js
|
@ -15,21 +15,14 @@ if (process.env.OPENAI_ORG_ID) {
|
||||||
const openai = new OpenAIApi(openAiConfig);
|
const openai = new OpenAIApi(openAiConfig);
|
||||||
|
|
||||||
|
|
||||||
export async function sendRequest(turns, systemMessage, stop_seq) {
|
export async function sendRequest(turns, systemMessage, stop_seq='***') {
|
||||||
|
|
||||||
let messages = [{'role': 'system', 'content': systemMessage}];
|
let messages = [{'role': 'system', 'content': systemMessage}].concat(turns);
|
||||||
for (let i = 0; i < turns.length; i++) {
|
|
||||||
if (i % 2 == 0) {
|
|
||||||
messages.push({'role': 'user', 'content': turns[i]});
|
|
||||||
} else {
|
|
||||||
messages.push({'role': 'assistant', 'content': turns[i]});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let res = null;
|
let res = null;
|
||||||
try {
|
try {
|
||||||
let completion = await openai.chat.completions.create({
|
let completion = await openai.chat.completions.create({
|
||||||
model: 'gpt-3.5-turbo',
|
model: 'gpt-4',
|
||||||
messages: messages,
|
messages: messages,
|
||||||
stop: stop_seq,
|
stop: stop_seq,
|
||||||
});
|
});
|
||||||
|
@ -37,7 +30,7 @@ export async function sendRequest(turns, systemMessage, stop_seq) {
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
res = 'I am sorry, I do not know how to respond to that.';
|
res = 'My brain disconnected, try again.';
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,60 +1,46 @@
|
||||||
var messages = [
|
let history_examples = [
|
||||||
{'source': 'all', 'message': 'Hey! What are you up to?'},
|
{'role': 'user', 'content': 'miner_32: Hey! What are you up to?'},
|
||||||
{'source': 'bot', 'message': `!action
|
{'role': 'assistant', 'content': 'Nothing much miner_32, what do you need?'},
|
||||||
\`\`\`
|
|
||||||
await skills.ExploreToFind(bot, 'coal_ore');
|
|
||||||
await skills.EquipItem(bot, 'wooden_pickaxe');
|
|
||||||
await skills.CollectBlock(bot, 'coal_ore', 10);
|
|
||||||
\`\`\`
|
|
||||||
|
|
||||||
I'm looking for coal. Have you seen any?`},
|
{'role': 'user', 'content': 'grombo_Xx: What do you see?'},
|
||||||
{'source': 'all', 'message': 'No, but can you help me collect wood?'},
|
{'role': 'assistant', 'content': 'Let me see... !blocks'},
|
||||||
{'source': 'bot', 'message': `!blocks
|
{'role': 'assistant', 'content': 'NEARBY_BLOCKS\n- oak_log\n- dirt\n- cobblestone'},
|
||||||
\`\`\`
|
{'role': 'assistant', 'content': 'I see some oak logs, dirt, and cobblestone.'},
|
||||||
NEARBY_BLOCKS
|
|
||||||
- oak_log
|
|
||||||
- dirt
|
|
||||||
- cobblestone
|
|
||||||
- birch_log
|
|
||||||
\`\`\`
|
|
||||||
|
|
||||||
Sure, do you want oak or birch?`},
|
{'role': 'user', 'content': 'zZZn98: come here'},
|
||||||
{'source': 'all', 'message': 'Thanks! Either is fine.'},
|
{'role': 'assistant', 'content': '```// I am going to navigate to zZZn98.\nreturn await skills.goToPlayer(bot, "zZZn98");```'},
|
||||||
{'source': 'bot', 'message': `I'll do that now.
|
|
||||||
|
|
||||||
!execute
|
{'role': 'user', 'content': 'hanky: collect some sand for me please'},
|
||||||
\`\`\`
|
{'role': 'assistant', 'content': 'Collecting sand...```// I am going to collect 3 sand and give to hanky.\n\
|
||||||
while (true) {
|
await skills.collectBlock(bot, "sand");\nreturn await skills.giveToPlayer(bot, "sand", "hanky");```'},
|
||||||
await skills.CollectBlock(bot, 'oak_log', 1);
|
|
||||||
await skills.goToPlayer(bot, 'username');
|
|
||||||
await skills.DropItem(bot, 'oak_log', 1);
|
|
||||||
}
|
|
||||||
\`\`\``}
|
|
||||||
];
|
|
||||||
|
|
||||||
|
{'role': 'user', 'content': 'sarah_O.o: can you do a dance for me?'},
|
||||||
|
{'role': 'assistant', 'content': "I don't know how to do that."},
|
||||||
|
|
||||||
export function addEvent(source, message) {
|
{'role': 'user', 'content': 'hanky: kill that zombie!'},
|
||||||
messages.push({source, message});
|
{'role': 'assistant', 'content': "I'm attacking! ```//I'm going to attack the nearest zombie.\n\
|
||||||
|
return await skills.attackMob(bot, 'zombie');```"},
|
||||||
|
|
||||||
|
{'role': 'user', 'content': 'billybob: stop what you are doing'},
|
||||||
|
{'role': 'assistant', 'content': '```// I am going to write nothing to clear my code\n return true;```'},
|
||||||
|
]
|
||||||
|
|
||||||
|
export class History {
|
||||||
|
constructor(agent) {
|
||||||
|
this.agent = agent;
|
||||||
|
this.turns = history_examples;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getHistory() {
|
||||||
|
return this.turns;
|
||||||
|
}
|
||||||
|
|
||||||
export function getHistory(source) {
|
add(name, content) {
|
||||||
let res = [];
|
let role = 'assistant';
|
||||||
let lastSource = null;
|
if (name !== this.agent.name) {
|
||||||
for (let i = 0; i < messages.length; i++) {
|
role = 'user';
|
||||||
if (lastSource != source && (messages[i].source == source || messages[i].source == 'all')) {
|
content = `${name}: ${content}`;
|
||||||
res.push(messages[i].message);
|
}
|
||||||
lastSource = source;
|
this.turns.push({role, content});
|
||||||
} else if (lastSource == source && (messages[i].source == source || messages[i].source == 'all')) {
|
|
||||||
res[-1] += '\n\n' + messages[i].message;
|
|
||||||
} else if (lastSource == source && messages[i].source == 'bot') {
|
|
||||||
res.push(messages[i].message);
|
|
||||||
lastSource = 'bot';
|
|
||||||
} else if (lastSource == 'bot' && messages[i].source == 'bot') {
|
|
||||||
res[-1] += '\n\n' + messages[i].message;
|
|
||||||
} else {
|
|
||||||
lastSource = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,6 +1,23 @@
|
||||||
import minecraftData from 'minecraft-data';
|
import minecraftData from 'minecraft-data';
|
||||||
var mcdata = minecraftData('1.19.3');
|
import { createBot } from 'mineflayer';
|
||||||
|
import { pathfinder } from 'mineflayer-pathfinder';
|
||||||
|
import { plugin } from 'mineflayer-collectblock';
|
||||||
|
|
||||||
|
const mc_version = '1.19.3'
|
||||||
|
let mcdata = minecraftData(mc_version);
|
||||||
|
|
||||||
|
|
||||||
|
export function initBot(username) {
|
||||||
|
let bot = createBot({
|
||||||
|
host: 'localhost',
|
||||||
|
port: 55916,
|
||||||
|
username: username,
|
||||||
|
version: mc_version,
|
||||||
|
});
|
||||||
|
bot.loadPlugin(pathfinder)
|
||||||
|
bot.loadPlugin(plugin)
|
||||||
|
return bot;
|
||||||
|
}
|
||||||
|
|
||||||
export function getItemId(item) {
|
export function getItemId(item) {
|
||||||
return mcdata.itemsByName[item].id;
|
return mcdata.itemsByName[item].id;
|
||||||
|
|
77
utils/queries.js
Normal file
77
utils/queries.js
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
import { getStats, getInventory, getBlocks, getNearbyEntities, getCraftable } from './context.js';
|
||||||
|
|
||||||
|
const pad = (str) => {
|
||||||
|
return '\n' + str + '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
const queryList = [
|
||||||
|
{
|
||||||
|
name: "!stats",
|
||||||
|
description: "Get your bot's stats",
|
||||||
|
perform: function (agent) {
|
||||||
|
return pad(getStats(agent.bot));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "!inventory",
|
||||||
|
description: "Get your bot's inventory.",
|
||||||
|
perform: function (agent) {
|
||||||
|
return pad(getInventory(agent.bot));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "!blocks",
|
||||||
|
description: "Get the blocks near the bot.",
|
||||||
|
perform: function (agent) {
|
||||||
|
return pad(getBlocks(agent.bot));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "!craftable",
|
||||||
|
description: "Get the craftable items with the bot's inventory.",
|
||||||
|
perform: function (agent) {
|
||||||
|
return pad(getCraftable(agent.bot));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "!entities",
|
||||||
|
description: "Get the nearby players and entities.",
|
||||||
|
perform: function (agent) {
|
||||||
|
return pad(getNearbyEntities(agent.bot));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "!action",
|
||||||
|
description: "Get the currently executing code.",
|
||||||
|
perform: function (agent) {
|
||||||
|
return pad("Current code:\n`" + agent.coder.current_code +"`");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const queryMap = {};
|
||||||
|
for (let query of queryList) {
|
||||||
|
queryMap[query.name] = query;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getQuery(name) {
|
||||||
|
return queryMap[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function containsQuery(message) {
|
||||||
|
for (let query of queryList) {
|
||||||
|
if (message.includes(query.name)) {
|
||||||
|
return query.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getQueryDocs() {
|
||||||
|
let docs = `\n*QUERY DOCS\n You can use the following commands to query for information about the world.
|
||||||
|
Use the query name in your response and the next input will have the requested information.\n`;
|
||||||
|
for (let query of queryList) {
|
||||||
|
docs += query.name + ': ' + query.description + '\n';
|
||||||
|
}
|
||||||
|
return docs + '*\n';
|
||||||
|
}
|
19
utils/skill_library.js
Normal file
19
utils/skill_library.js
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import * as skills from './skills.js';
|
||||||
|
import * as world from './world.js';
|
||||||
|
|
||||||
|
export function getSkillDocs() {
|
||||||
|
let docstring = "\n*SKILL DOCS\nThese skills are javascript functions that can be called with a js function by writing a code block. Ex: '```// write description comment and code here```' \n\
|
||||||
|
Your code block should return a bool indicating if the task was completed successfully. It will return true if you don't write a return statement.\n";
|
||||||
|
for (let skillFunc of Object.values(world).concat(Object.values(skills))) {
|
||||||
|
let str = skillFunc.toString();
|
||||||
|
if (str.includes('/**')){
|
||||||
|
docstring += skillFunc.name;
|
||||||
|
docstring += str.substring(str.indexOf('/**')+3, str.indexOf('**/')) + '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return docstring + '*\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function containsCodeBlock(message) {
|
||||||
|
return message.indexOf('```') !== -1;
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ import { getCraftingTable, getInventoryCounts, getInventoryStacks, getNearbyMobs
|
||||||
import pf from 'mineflayer-pathfinder';
|
import pf from 'mineflayer-pathfinder';
|
||||||
|
|
||||||
|
|
||||||
|
export async function craftItem(bot, itemName) {
|
||||||
/**
|
/**
|
||||||
* Attempt to craft the given item.
|
* Attempt to craft the given item.
|
||||||
* @param {MinecraftBot} bot, reference to the minecraft bot.
|
* @param {MinecraftBot} bot, reference to the minecraft bot.
|
||||||
|
@ -11,7 +12,6 @@ import pf from 'mineflayer-pathfinder';
|
||||||
* @example
|
* @example
|
||||||
* await skills.craftItem(bot, "wooden_pickaxe");
|
* await skills.craftItem(bot, "wooden_pickaxe");
|
||||||
**/
|
**/
|
||||||
export async function craftItem(bot, itemName) {
|
|
||||||
const table = getCraftingTable(bot);
|
const table = getCraftingTable(bot);
|
||||||
let recipes = bot.recipesFor(getItemId(itemName), null, 1, table);
|
let recipes = bot.recipesFor(getItemId(itemName), null, 1, table);
|
||||||
await bot.craft(recipes[0], 1, null);
|
await bot.craft(recipes[0], 1, null);
|
||||||
|
@ -19,6 +19,7 @@ export async function craftItem(bot, itemName) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export async function attackMob(bot, mobType) {
|
||||||
/**
|
/**
|
||||||
* Attack mob of the given type.
|
* Attack mob of the given type.
|
||||||
* @param {MinecraftBot} bot, reference to the minecraft bot.
|
* @param {MinecraftBot} bot, reference to the minecraft bot.
|
||||||
|
@ -27,7 +28,6 @@ export async function craftItem(bot, itemName) {
|
||||||
* @example
|
* @example
|
||||||
* await skills.attackMob(bot, "zombie");
|
* await skills.attackMob(bot, "zombie");
|
||||||
**/
|
**/
|
||||||
export async function attackMob(bot, mobType) {
|
|
||||||
const mobs = getNearbyMobs(bot);
|
const mobs = getNearbyMobs(bot);
|
||||||
for (let i = 0; i < mobs.length; i++) {
|
for (let i = 0; i < mobs.length; i++) {
|
||||||
if (mobs[i].mobType == mobType) {
|
if (mobs[i].mobType == mobType) {
|
||||||
|
@ -39,6 +39,7 @@ export async function attackMob(bot, mobType) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export async function collectBlock(bot, blockType) {
|
||||||
/**
|
/**
|
||||||
* Collect one of the given block type.
|
* Collect one of the given block type.
|
||||||
* @param {MinecraftBot} bot, reference to the minecraft bot.
|
* @param {MinecraftBot} bot, reference to the minecraft bot.
|
||||||
|
@ -47,7 +48,6 @@ export async function attackMob(bot, mobType) {
|
||||||
* @example
|
* @example
|
||||||
* await skills.collectBlock(bot, "oak_log");
|
* await skills.collectBlock(bot, "oak_log");
|
||||||
**/
|
**/
|
||||||
export async function collectBlock(bot, blockType) {
|
|
||||||
const blocks = getNearbyBlocks(bot);
|
const blocks = getNearbyBlocks(bot);
|
||||||
for (let i = 0; i < blocks.length; i++) {
|
for (let i = 0; i < blocks.length; i++) {
|
||||||
if (blocks[i].name == blockType) {
|
if (blocks[i].name == blockType) {
|
||||||
|
@ -59,6 +59,7 @@ export async function collectBlock(bot, blockType) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export async function breakBlockAt(bot, x, y, z) {
|
||||||
/**
|
/**
|
||||||
* Break the block at the given position. Will use the bot's equipped item.
|
* Break the block at the given position. Will use the bot's equipped item.
|
||||||
* @param {MinecraftBot} bot, reference to the minecraft bot.
|
* @param {MinecraftBot} bot, reference to the minecraft bot.
|
||||||
|
@ -67,10 +68,9 @@ export async function collectBlock(bot, blockType) {
|
||||||
* @param {number} z, the z coordinate of the block to break.
|
* @param {number} z, the z coordinate of the block to break.
|
||||||
* @returns {Promise<boolean>} true if the block was broken, false otherwise.
|
* @returns {Promise<boolean>} true if the block was broken, false otherwise.
|
||||||
* @example
|
* @example
|
||||||
* let position = getPosition(bot);
|
* let position = world.getPosition(bot);
|
||||||
* await skills.breakBlockAt(bot, position.x, position.y - 1, position.x);
|
* await skills.breakBlockAt(bot, position.x, position.y - 1, position.x);
|
||||||
**/
|
**/
|
||||||
export async function breakBlockAt(bot, x, y, z) {
|
|
||||||
let current = bot.blockAt({ x: x, y: y, z: z });
|
let current = bot.blockAt({ x: x, y: y, z: z });
|
||||||
if (current.name != 'air')
|
if (current.name != 'air')
|
||||||
await bot.dig(current, true);
|
await bot.dig(current, true);
|
||||||
|
@ -78,6 +78,7 @@ export async function breakBlockAt(bot, x, y, z) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export async function placeBlock(bot, blockType, x, y, z) {
|
||||||
/**
|
/**
|
||||||
* Place the given block type at the given position.
|
* Place the given block type at the given position.
|
||||||
* @param {MinecraftBot} bot, reference to the minecraft bot.
|
* @param {MinecraftBot} bot, reference to the minecraft bot.
|
||||||
|
@ -87,11 +88,9 @@ export async function breakBlockAt(bot, x, y, z) {
|
||||||
* @param {number} z, the z coordinate to place the block at.
|
* @param {number} z, the z coordinate to place the block at.
|
||||||
* @returns {Promise<boolean>} true if the block was placed, false otherwise.
|
* @returns {Promise<boolean>} true if the block was placed, false otherwise.
|
||||||
* @example
|
* @example
|
||||||
* let position = getPosition(bot);
|
* let position = world.getPosition(bot);
|
||||||
* await skills.placeBlock(bot, "oak_log", position.x + 1, position.y, position.x);
|
* await skills.placeBlock(bot, "oak_log", position.x + 1, position.y, position.x);
|
||||||
**/
|
**/
|
||||||
export async function placeBlock(bot, blockType, x, y, z) {
|
|
||||||
|
|
||||||
let referenceBlock = null;
|
let referenceBlock = null;
|
||||||
let refVec = null;
|
let refVec = null;
|
||||||
if (bot.blockAt({ x: x + 1, y: y, z: z }).name != "air") {
|
if (bot.blockAt({ x: x + 1, y: y, z: z }).name != "air") {
|
||||||
|
@ -133,6 +132,7 @@ export async function placeBlock(bot, blockType, x, y, z) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export async function equipItem(bot, itemName) {
|
||||||
/**
|
/**
|
||||||
* Equip the given item or block.
|
* Equip the given item or block.
|
||||||
* @param {MinecraftBot} bot, reference to the minecraft bot.
|
* @param {MinecraftBot} bot, reference to the minecraft bot.
|
||||||
|
@ -141,7 +141,6 @@ export async function placeBlock(bot, blockType, x, y, z) {
|
||||||
* @example
|
* @example
|
||||||
* await skills.equipItem(bot, "wooden_pickaxe");
|
* await skills.equipItem(bot, "wooden_pickaxe");
|
||||||
**/
|
**/
|
||||||
export async function equipItem(bot, itemName) {
|
|
||||||
let item = null;
|
let item = null;
|
||||||
for (let stack of getInventoryStacks(bot)) {
|
for (let stack of getInventoryStacks(bot)) {
|
||||||
if (stack.name == itemName) {
|
if (stack.name == itemName) {
|
||||||
|
@ -156,6 +155,7 @@ export async function equipItem(bot, itemName) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export async function goToPosition(bot, x, y, z) {
|
||||||
/**
|
/**
|
||||||
* Navigate to the given position.
|
* Navigate to the given position.
|
||||||
* @param {MinecraftBot} bot, reference to the minecraft bot.
|
* @param {MinecraftBot} bot, reference to the minecraft bot.
|
||||||
|
@ -164,10 +164,9 @@ export async function equipItem(bot, itemName) {
|
||||||
* @param {number} z, the z coordinate to navigate to. If null, the bot's current z coordinate will be used.
|
* @param {number} z, the z coordinate to navigate to. If null, the bot's current z coordinate will be used.
|
||||||
* @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 = getPosition(bot);
|
* let position = world.getPosition(bot);
|
||||||
* await skills.goToPosition(bot, position.x, position.y, position.x + 20);
|
* await skills.goToPosition(bot, position.x, position.y, position.x + 20);
|
||||||
**/
|
**/
|
||||||
export async function goToPosition(bot, x, y, z) {
|
|
||||||
if (x == null) x = bot.entity.position.x;
|
if (x == null) x = bot.entity.position.x;
|
||||||
if (y == null) y = bot.entity.position.y;
|
if (y == null) y = bot.entity.position.y;
|
||||||
if (z == null) z = bot.entity.position.z;
|
if (z == null) z = bot.entity.position.z;
|
||||||
|
@ -178,6 +177,7 @@ export async function goToPosition(bot, x, y, z) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export async function giveToPlayer(bot, itemType, username) {
|
||||||
/**
|
/**
|
||||||
* Give one of the specified item to the specified player
|
* Give one of the specified item to the specified player
|
||||||
* @param {MinecraftBot} bot, reference to the minecraft bot.
|
* @param {MinecraftBot} bot, reference to the minecraft bot.
|
||||||
|
@ -187,7 +187,6 @@ export async function goToPosition(bot, x, y, z) {
|
||||||
* @example
|
* @example
|
||||||
* await skills.giveToPlayer(bot, "oak_log", "player1");
|
* await skills.giveToPlayer(bot, "oak_log", "player1");
|
||||||
**/
|
**/
|
||||||
export async function giveToPlayer(bot, itemType, username) {
|
|
||||||
let player = bot.players[username].entity
|
let player = bot.players[username].entity
|
||||||
if (!player)
|
if (!player)
|
||||||
return false;
|
return false;
|
||||||
|
@ -201,6 +200,7 @@ export async function giveToPlayer(bot, itemType, username) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export async function goToPlayer(bot, username) {
|
||||||
/**
|
/**
|
||||||
* Navigate to the given player.
|
* Navigate to the given player.
|
||||||
* @param {MinecraftBot} bot, reference to the minecraft bot.
|
* @param {MinecraftBot} bot, reference to the minecraft bot.
|
||||||
|
@ -209,7 +209,6 @@ export async function giveToPlayer(bot, itemType, username) {
|
||||||
* @example
|
* @example
|
||||||
* await skills.goToPlayer(bot, "player");
|
* await skills.goToPlayer(bot, "player");
|
||||||
**/
|
**/
|
||||||
export async function goToPlayer(bot, username) {
|
|
||||||
let player = bot.players[username].entity
|
let player = bot.players[username].entity
|
||||||
if (!player)
|
if (!player)
|
||||||
return false;
|
return false;
|
||||||
|
@ -219,3 +218,24 @@ export async function goToPlayer(bot, username) {
|
||||||
bot.pathfinder.setGoal(new pf.goals.GoalNear(pos.x, pos.y, pos.z, 3));
|
bot.pathfinder.setGoal(new pf.goals.GoalNear(pos.x, pos.y, pos.z, 3));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export async function followPlayer(bot, username) {
|
||||||
|
/**
|
||||||
|
* Follow the given player endlessly.
|
||||||
|
* @param {MinecraftBot} bot, reference to the minecraft bot.
|
||||||
|
* @param {string} username, the username of the player to follow.
|
||||||
|
* @returns {Promise<boolean>} true if the player was found, false otherwise.
|
||||||
|
* @example
|
||||||
|
* await skills.followPlayer(bot, "player");
|
||||||
|
**/
|
||||||
|
let player = bot.players[username].entity
|
||||||
|
if (!player)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bot.pathfinder.setMovements(new pf.Movements(bot));
|
||||||
|
let pos = player.position;
|
||||||
|
bot.pathfinder.setGoal(new pf.goals.GoalFollow(player, 3), true);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
|
@ -81,6 +81,7 @@ export function getInventoryStacks(bot) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function getInventoryCounts(bot) {
|
||||||
/**
|
/**
|
||||||
* Get an object representing the bot's inventory.
|
* Get an object representing the bot's inventory.
|
||||||
* @param {Bot} bot - The bot to get the inventory for.
|
* @param {Bot} bot - The bot to get the inventory for.
|
||||||
|
@ -90,7 +91,6 @@ export function getInventoryStacks(bot) {
|
||||||
* let oakLogCount = inventory['oak_log'];
|
* let oakLogCount = inventory['oak_log'];
|
||||||
* let hasWoodenPickaxe = inventory['wooden_pickaxe'] > 0;
|
* let hasWoodenPickaxe = inventory['wooden_pickaxe'] > 0;
|
||||||
**/
|
**/
|
||||||
export function getInventoryCounts(bot) {
|
|
||||||
let inventory = {};
|
let inventory = {};
|
||||||
for (const item of getInventoryStacks(bot)) {
|
for (const item of getInventoryStacks(bot)) {
|
||||||
if (inventory.hasOwnProperty(item.name)) {
|
if (inventory.hasOwnProperty(item.name)) {
|
||||||
|
@ -113,6 +113,7 @@ export function getInventoryCounts(bot) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function getPosition(bot) {
|
||||||
/**
|
/**
|
||||||
* Get your position in the world (Note that y is vertical).
|
* Get your position in the world (Note that y is vertical).
|
||||||
* @param {Bot} bot - The bot to get the position for.
|
* @param {Bot} bot - The bot to get the position for.
|
||||||
|
@ -121,11 +122,11 @@ export function getInventoryCounts(bot) {
|
||||||
* let position = world.getPosition(bot);
|
* let position = world.getPosition(bot);
|
||||||
* let x = position.x;
|
* let x = position.x;
|
||||||
**/
|
**/
|
||||||
export function getPosition(bot) {
|
|
||||||
return bot.entity.position;
|
return bot.entity.position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function getNearbyMobTypes(bot) {
|
||||||
/**
|
/**
|
||||||
* Get a list of all nearby mob types.
|
* Get a list of all nearby mob types.
|
||||||
* @param {Bot} bot - The bot to get nearby mobs for.
|
* @param {Bot} bot - The bot to get nearby mobs for.
|
||||||
|
@ -133,7 +134,6 @@ export function getPosition(bot) {
|
||||||
* @example
|
* @example
|
||||||
* let mobs = world.getNearbyMobTypes(bot);
|
* let mobs = world.getNearbyMobTypes(bot);
|
||||||
**/
|
**/
|
||||||
export function getNearbyMobTypes(bot) {
|
|
||||||
let mobs = getNearbyMobs(bot, 16);
|
let mobs = getNearbyMobs(bot, 16);
|
||||||
let found = [];
|
let found = [];
|
||||||
for (let i = 0; i < mobs.length; i++) {
|
for (let i = 0; i < mobs.length; i++) {
|
||||||
|
@ -145,6 +145,7 @@ export function getNearbyMobTypes(bot) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function getNearbyPlayerNames(bot) {
|
||||||
/**
|
/**
|
||||||
* Get a list of all nearby player names.
|
* Get a list of all nearby player names.
|
||||||
* @param {Bot} bot - The bot to get nearby players for.
|
* @param {Bot} bot - The bot to get nearby players for.
|
||||||
|
@ -152,7 +153,6 @@ export function getNearbyMobTypes(bot) {
|
||||||
* @example
|
* @example
|
||||||
* let players = world.getNearbyPlayerNames(bot);
|
* let players = world.getNearbyPlayerNames(bot);
|
||||||
**/
|
**/
|
||||||
export function getNearbyPlayerNames(bot) {
|
|
||||||
let players = getNearbyPlayers(bot, 16);
|
let players = getNearbyPlayers(bot, 16);
|
||||||
let found = [];
|
let found = [];
|
||||||
for (let i = 0; i < players.length; i++) {
|
for (let i = 0; i < players.length; i++) {
|
||||||
|
@ -164,6 +164,7 @@ export function getNearbyPlayerNames(bot) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function getNearbyBlockTypes(bot) {
|
||||||
/**
|
/**
|
||||||
* Get a list of all nearby block names.
|
* Get a list of all nearby block names.
|
||||||
* @param {Bot} bot - The bot to get nearby blocks for.
|
* @param {Bot} bot - The bot to get nearby blocks for.
|
||||||
|
@ -171,7 +172,6 @@ export function getNearbyPlayerNames(bot) {
|
||||||
* @example
|
* @example
|
||||||
* let blocks = world.getNearbyBlockTypes(bot);
|
* let blocks = world.getNearbyBlockTypes(bot);
|
||||||
**/
|
**/
|
||||||
export function getNearbyBlockTypes(bot) {
|
|
||||||
let blocks = getNearbyBlocks(bot, 16);
|
let blocks = getNearbyBlocks(bot, 16);
|
||||||
let found = [];
|
let found = [];
|
||||||
for (let i = 0; i < blocks.length; i++) {
|
for (let i = 0; i < blocks.length; i++) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue