// 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 }