Updated logic for Idle and Observe.
All checks were successful
Deploy Cletus Bot / deploy (push) Successful in 25s

This commit is contained in:
roberts 2025-05-10 18:19:59 -05:00
parent dcee986a96
commit d8ee8d6728
4 changed files with 116 additions and 55 deletions

View file

@ -0,0 +1,41 @@
const { getBot } = require('../core/context');
const { saveMemory } = require('../memory');
const db = require('../db');
// Define what kinds of blocks to remember. This should probably be a variable later so that I can add to this list.
const INTERESTING_BLOCKS = [
'coal_ore', 'iron_ore', 'diamond_ore', 'gold_ore', 'emerald_ore',
'redstone_ore', 'lapis_ore', 'copper_ore',
'oak_log', 'birch_log', 'spruce_log',
'crafting_table', 'furnace', 'chest', 'anvil',
'enchanting_table', 'lectern', 'bell',
'bed', 'beacon', 'portal'
];
module.exports = async function logSurroundings() {
const bot = getBot();
if (!bot) return;
const found = bot.findBlocks({
matching: block => INTERESTING_BLOCKS.includes(block.name),
maxDistance: 12,
count: 10
});
for (const pos of found) {
const block = bot.blockAt(pos);
if (!block || !block.name) continue;
const label = `found:${block.name}:${pos.x},${pos.y},${pos.z}`;
const memoryData = {
name: block.name,
position: pos
};
saveMemory(db, label, memoryData);
}
if (found.length > 0) {
bot.chat(`I noticed ${found.length} interesting blocks nearby.`);
}
};

View file

@ -1,14 +1,18 @@
// states/ActOnMemory.js
const { chatWithAI } = require('../lib/ai-helper');
const { getBot } = require('../core/context');
const { getBot, getStateMachine } = require('../core/context');
const config = require('../config.json');
module.exports = async function ActOnMemory() {
const bot = getBot();
console.log('[STATE] ActOnMemory');
const prompt = 'You just died. Based on what you remember, what should you do next?';
const response = await chatWithAI(prompt, config.ai);
const bot = getBot();
bot.chat(response);
setTimeout(async () => {
getStateMachine().transition('Idle');
}, 5000);
};

View file

@ -1,5 +1,6 @@
// states/Idle.js
const { getBot } = require('../core/context');
const { GoalNear } = require('mineflayer-pathfinder').goals;
const { getHomeZone } = require('../memory/locations');
const db = require('../db');
@ -8,66 +9,74 @@ module.exports = async function Idle() {
const bot = getBot();
console.log('[STATE] Idle');
getHomeZone(db, async (err, zone) => {
const fallbackCenter = { x: 100, y: 64, z: 100 };
const fallbackBounds = { x: 20, y: 10, z: 20 };
return new Promise(resolve => {
getHomeZone(db, async (err, zone) => {
const fallbackCenter = { x: 100, y: 64, z: 100 };
const fallbackBounds = { x: 20, y: 10, z: 20 };
const center = zone?.center || fallbackCenter;
const bounds = zone?.bounds || fallbackBounds;
const safeRadius = Math.min(bounds.x, bounds.z);
const center = zone?.center || fallbackCenter;
const bounds = zone?.bounds || fallbackBounds;
const safeRadius = Math.min(bounds.x, bounds.z);
const actionRoll = Math.floor(Math.random() * 3);
const actionRoll = Math.floor(Math.random() * 3);
if (actionRoll === 0) {
const grass = bot.findBlock({
matching: block => block.name === 'tall_grass',
maxDistance: safeRadius
});
if (actionRoll === 0) {
const grass = bot.findBlock({
matching: block => block.name === 'tall_grass',
maxDistance: safeRadius
});
if (grass) {
await bot.pathfinder.setGoal(new GoalNear(grass.position.x, grass.position.y, grass.position.z, 1));
try {
await bot.dig(grass);
bot.chat("Trimming grass.");
} catch {}
}
} else if (actionRoll === 1) {
const crops = bot.findBlocks({
matching: block => ['wheat', 'carrots', 'potatoes'].includes(block.name),
maxDistance: safeRadius,
count: 5
});
for (const pos of crops) {
const crop = bot.blockAt(pos);
if (crop.metadata === 7) {
await bot.pathfinder.setGoal(new GoalNear(pos.x, pos.y, pos.z, 1));
if (grass) {
await bot.pathfinder.setGoal(new GoalNear(grass.position.x, grass.position.y, grass.position.z, 1));
try {
await bot.dig(crop);
bot.chat("Harvesting a crop.");
// TODO: Replanting logic needs to be added here. This might be a state or a task.. not sure yet.
await bot.dig(grass);
bot.chat("Trimming grass.");
} catch {}
break;
}
} else if (actionRoll === 1) {
const crops = bot.findBlocks({
matching: block => ['wheat', 'carrots', 'potatoes'].includes(block.name),
maxDistance: safeRadius,
count: 5
});
for (const pos of crops) {
const crop = bot.blockAt(pos);
if (crop.metadata === 7) {
await bot.pathfinder.setGoal(new GoalNear(pos.x, pos.y, pos.z, 1));
try {
await bot.dig(crop);
bot.chat("Harvesting a crop.");
// TODO: Replanting logic needs to be added here. This might be a state or a task.. not sure yet.
} catch {}
break;
}
}
} else {
const mob = Object.values(bot.entities).find(e =>
e.type === 'mob' &&
e.position.distanceTo(bot.entity.position) <= safeRadius &&
e.username !== bot.username
);
if (mob) {
bot.chat(`Engaging ${mob.name}.`);
bot.attack(mob);
} else {
const dx = Math.floor(Math.random() * safeRadius * 2 - safeRadius);
const dz = Math.floor(Math.random() * safeRadius * 2 - safeRadius);
const pos = bot.entity.position.offset(dx, 0, dz);
bot.pathfinder.setGoal(new GoalNear(pos.x, pos.y, pos.z, 1));
}
}
} else {
const mob = Object.values(bot.entities).find(e =>
e.type === 'mob' &&
e.position.distanceTo(bot.entity.position) <= safeRadius &&
e.username !== bot.username
);
if (mob) {
bot.chat(`Engaging ${mob.name}.`);
bot.attack(mob);
} else {
const dx = Math.floor(Math.random() * safeRadius * 2 - safeRadius);
const dz = Math.floor(Math.random() * safeRadius * 2 - safeRadius);
const pos = bot.entity.position.offset(dx, 0, dz);
bot.pathfinder.setGoal(new GoalNear(pos.x, pos.y, pos.z, 1));
}
}
setTimeout(() => {
getStateMachine().transition('Observe');
resolve();
}, 10000 );
});
});
};

View file

@ -13,4 +13,11 @@ module.exports = async function Observe() {
const response = await chatWithAI(msg, config.ai);
bot.chat(response);
await logSurroundings();
setTimeout(() => {
getStateMachine().transition('Idle');
}, 10000);
};