angram/lib/plugins/statemachine.js

115 lines
4.1 KiB
JavaScript
Raw Normal View History

// Load your dependency plugins.
const {pathfinder} = require('mineflayer-pathfinder')
// bot.loadPlugin(require('prismarine-viewer').mineflayer)
// const mineflayerViewer = require('prismarine-viewer').mineflayer
// Import required behaviors.
const {
StateTransition,
BotStateMachine,
EntityFilters,
BehaviorFollowEntity,
BehaviorLookAtEntity,
BehaviorGetClosestEntity,
NestedStateMachine,
BehaviorIdle,
StateMachineWebserver,
} = require("mineflayer-statemachine");
// TODO chat
// wait for our bot to login.
function statemachineInit() {
cfg.botAddress = new RegExp(`^${bot.username} (!.+)`)
// This targets object is used to pass data between different states. It can be left empty.
const targets = new Object();
// Create our states
const getClosestPlayer = new BehaviorGetClosestEntity(
bot, targets, entity => EntityFilters().PlayersOnly(entity) && bot.entity.position.distanceTo(entity.position) <= 50 ); // && a.username !== bot.username);
const followPlayer = new BehaviorFollowEntity(bot, targets);
const lookAtPlayer = new BehaviorLookAtEntity(bot, targets);
const stay = new BehaviorIdle();
// Create our transitions
const transitions = [
// We want to start following the player immediately after finding them.
// Since getClosestPlayer finishes instantly, shouldTransition() should always return true.
new StateTransition({
parent: getClosestPlayer,
child: followPlayer,
onTransition: (quiet) => quiet || bot.chat(`Hi ${targets.entity.username}!`),
shouldTransition: () => bot.entity.position.distanceTo(targets.entity.position) <= 50,
// shouldTransition: () => getClosestPlayer.distanceToTarget() < 100 || console.info("player too far!") && false,
}),
// If the distance to the player is less than two blocks, switch from the followPlayer
// state to the lookAtPlayer state.
new StateTransition({
parent: followPlayer,
child: lookAtPlayer,
// onTransition: () => console.log(targets),
shouldTransition: () => followPlayer.distanceToTarget() < 2,
}),
// If the distance to the player is more than two blocks, switch from the lookAtPlayer
// state to the followPlayer state.
new StateTransition({
parent: lookAtPlayer,
child: followPlayer,
shouldTransition: () => lookAtPlayer.distanceToTarget() >= 5,
}),
new StateTransition({
parent: lookAtPlayer,
child: stay,
onTransition: () => bot.chat("ok, staying"),
// shouldTransition: () => true,
}),
new StateTransition({
parent: stay,
child: getClosestPlayer,
// shouldTransition: () => Math.random() > 0.01,
// shouldTransition: () => Math.random() > 0.1 && getClosestPlayer.distanceToTarget() < 2,
}),
];
// Now we just wrap our transition list in a nested state machine layer. We want the bot
// to start on the getClosestPlayer state, so we'll specify that here.
const rootLayer = new NestedStateMachine(transitions, getClosestPlayer, stay);
// We can start our state machine simply by creating a new instance.
cfg.stateMachines.follow = new BotStateMachine(bot, rootLayer);
const webserver = new StateMachineWebserver(bot, cfg.stateMachines.follow);
webserver.startServer();
// mineflayerViewer(bot, { port: 3000 })
// const path = [bot.entity.position.clone()]
// bot.on('move', () => {
// if (path[path.length - 1].distanceTo(bot.entity.position) > 1) {
// path.push(bot.entity.position.clone())
// bot.viewer.drawLine('path', path)
// }
// })
}
const load = (config) => {
cfg = config
bot = cfg.bot
// cfg.inventory = {
// auto: true,
// quiet: false
// }
// bot.on('chat', inventory)
bot.loadPlugin(pathfinder)
// statemachineInit()
}
const unload = () => {
// bot.off('chat', inventory)
}
module.exports = { load, unload }