mirror of
https://github.com/kolbytn/mindcraft.git
synced 2025-07-20 15:05:18 +02:00
modes are async, added clearpath check
This commit is contained in:
parent
287f13c5b5
commit
bff811d1c3
3 changed files with 40 additions and 17 deletions
|
@ -152,13 +152,17 @@ export class Agent {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.self_defense = true;
|
// This update loop ensures that each update() is called one at a time, even if it takes longer than the interval
|
||||||
this.defending = false;
|
const INTERVAL = 300;
|
||||||
this._pause_defending = false;
|
setTimeout(async () => {
|
||||||
|
while (true) {
|
||||||
// set interval every 300ms to update the bot's state
|
let start = Date.now();
|
||||||
this.update_interval = setInterval(async () => {
|
await this.bot.modes.update();
|
||||||
this.bot.modes.update();
|
let remaining = INTERVAL - (Date.now() - start);
|
||||||
}, 300);
|
if (remaining > 0) {
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, remaining));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, INTERVAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,17 +8,20 @@ import * as world from './world.js';
|
||||||
// paused: whether the mode is paused by another action that overrides the behavior (eg followplayer implements its own self defense)
|
// paused: whether the mode is paused by another action that overrides the behavior (eg followplayer implements its own self defense)
|
||||||
// update: the function that is called every tick (if on is true)
|
// update: the function that is called every tick (if on is true)
|
||||||
// when a mode is active, it will trigger an action to be performed but won't wait for it to return output
|
// when a mode is active, it will trigger an action to be performed but won't wait for it to return output
|
||||||
|
|
||||||
// the order of this list matters! first modes will be prioritized
|
// the order of this list matters! first modes will be prioritized
|
||||||
|
// while update functions are async, they should *not* be awaited longer than ~100ms as it will block the update loop
|
||||||
|
// to perform longer actions, use the execute function which won't block the update loop
|
||||||
const modes = [
|
const modes = [
|
||||||
{
|
{
|
||||||
name: 'self_defense',
|
name: 'self_defense',
|
||||||
description: 'Automatically attack nearby enemies. Interrupts other actions.',
|
description: 'Automatically attack nearby enemies. Interrupts other actions.',
|
||||||
on: true,
|
on: true,
|
||||||
active: false,
|
active: false,
|
||||||
update: function (agent) {
|
update: async 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 => skills.isHostile(entity), 8);
|
||||||
if (enemy) {
|
if (enemy && await world.isClearPath(agent.bot, enemy)) {
|
||||||
agent.bot.chat(`Fighting ${enemy.name}!`);
|
agent.bot.chat(`Fighting ${enemy.name}!`);
|
||||||
execute(this, agent, async () => {
|
execute(this, agent, async () => {
|
||||||
await skills.defendSelf(agent.bot, 8);
|
await skills.defendSelf(agent.bot, 8);
|
||||||
|
@ -31,10 +34,10 @@ const modes = [
|
||||||
description: 'Automatically hunt nearby animals when idle.',
|
description: 'Automatically hunt nearby animals when idle.',
|
||||||
on: true,
|
on: true,
|
||||||
active: false,
|
active: false,
|
||||||
update: function (agent) {
|
update: async 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 => skills.isHuntable(entity), 8);
|
||||||
if (huntable) {
|
if (huntable && await world.isClearPath(agent.bot, huntable)) {
|
||||||
execute(this, agent, async () => {
|
execute(this, agent, async () => {
|
||||||
agent.bot.chat(`Hunting ${huntable.name}!`);
|
agent.bot.chat(`Hunting ${huntable.name}!`);
|
||||||
await skills.attackEntity(agent.bot, huntable);
|
await skills.attackEntity(agent.bot, huntable);
|
||||||
|
@ -48,10 +51,10 @@ const modes = [
|
||||||
description: 'Automatically collect nearby items when idle.',
|
description: 'Automatically collect nearby items when idle.',
|
||||||
on: true,
|
on: true,
|
||||||
active: false,
|
active: false,
|
||||||
update: function (agent) {
|
update: async function (agent) {
|
||||||
if (agent.idle) {
|
if (agent.idle) {
|
||||||
let item = world.getNearestEntityWhere(agent.bot, entity => entity.name === 'item', 8);
|
let item = world.getNearestEntityWhere(agent.bot, entity => entity.name === 'item', 4);
|
||||||
if (item) {
|
if (item && await world.isClearPath(agent.bot, item)) {
|
||||||
execute(this, agent, async () => {
|
execute(this, agent, async () => {
|
||||||
// wait 2 seconds for the item to settle
|
// wait 2 seconds for the item to settle
|
||||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||||
|
@ -174,7 +177,7 @@ class ModeController {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
update() {
|
async update() {
|
||||||
if (this.agent.idle) {
|
if (this.agent.idle) {
|
||||||
// other actions might pause a mode to override it
|
// other actions might pause a mode to override it
|
||||||
// when idle, unpause all modes
|
// when idle, unpause all modes
|
||||||
|
@ -185,7 +188,7 @@ class ModeController {
|
||||||
}
|
}
|
||||||
for (let mode of this.modes_list) {
|
for (let mode of this.modes_list) {
|
||||||
if (mode.on && !mode.paused) {
|
if (mode.on && !mode.paused) {
|
||||||
mode.update(this.agent);
|
await mode.update(this.agent);
|
||||||
if (mode.active) {
|
if (mode.active) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { getAllBlockIds } from '../utils/mcdata.js';
|
import { getAllBlockIds } from '../utils/mcdata.js';
|
||||||
|
import pf from 'mineflayer-pathfinder';
|
||||||
|
|
||||||
|
|
||||||
export function getNearestBlocks(bot, block_types, distance=16, count=1) {
|
export function getNearestBlocks(bot, block_types, distance=16, count=1) {
|
||||||
|
@ -206,3 +207,18 @@ export function getNearbyBlockTypes(bot, distance=16) {
|
||||||
}
|
}
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function isClearPath(bot, target) {
|
||||||
|
/**
|
||||||
|
* Check if there is a path to the target that requires no digging or placing blocks.
|
||||||
|
* @param {Bot} bot - The bot to get the path for.
|
||||||
|
* @param {Entity} target - The target to path to.
|
||||||
|
* @returns {boolean} - True if there is a clear path, false otherwise.
|
||||||
|
*/
|
||||||
|
let movements = new pf.Movements(bot)
|
||||||
|
movements.canDig = false;
|
||||||
|
movements.canPlaceOn = false;
|
||||||
|
let goal = new pf.goals.GoalNear(target.position.x, target.position.y, target.position.z, 1);
|
||||||
|
let path = await bot.pathfinder.getPathTo(movements, goal, 100);
|
||||||
|
return path.status === 'success';
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue