const mineflayer = require ( 'mineflayer' )
const { pathfinder , Movements , goals } = require ( 'mineflayer-pathfinder' )
const pvp = require ( 'mineflayer-pvp' ) . plugin
let cfg = { }
let bot = { }
let guardPos
const filterAllMobs = e => e . type === 'mob'
const filterPlayers = e => e . type === 'player'
const filterMods = e => e . type === 'player' && [ cfg . mods ] . includes ( e . username )
// const filterPassiveMobs = e => e.kind === 'Passive mobs'
const filterCreeper = e => e . mobType === 'Creeper'
// const filterCreeperOrEndermen = e => ['Creeper', 'EndderMen'].includes(e.mobType) //TODO endmen hostile by default?
const filterHostileMobs = e => e . kind === 'Hostile mobs'
// // not needed if detecting by kind
// && e.mobType !== 'Armor Stand' // Mojang classifies armor stands as mobs for some reason?
// Assign the given location to be guarded
function guardArea ( pos ) {
if ( pos ) {
cfg . guard . pos = guardPos = pos
// Check for new enemies to attack
// bot.off('physicTick', lookForMobs)
bot . off ( 'time' , lookForMobs )
bot . on ( 'time' , lookForMobs )
}
// We are not currently in combat, move to the guard pos
if ( ! bot . pvp . target && guardPos ) {
moveToGuardPos ( )
}
}
// Cancel all pathfinder and combat
function stopGuarding ( ) {
guardPos = cfg . guard . pos = null
bot . pvp . stop ( )
bot . pathfinder . setGoal ( null )
bot . off ( 'time' , lookForMobs )
// bot.off('physicTick', lookForMobs)
}
// Pathfinder to the guard position
function moveToGuardPos ( ) {
const mcData = require ( 'minecraft-data' ) ( bot . version )
bot . pathfinder . setMovements ( new Movements ( bot , mcData ) )
bot . pathfinder . setGoal ( new goals . GoalBlock ( guardPos . x , guardPos . y , guardPos . z ) )
}
// Called when the bot has killed it's target.
// () => {
// if (guardPos) {
// moveToGuardPos()
// }
// })
function lookForMobs ( ) {
if ( ! guardPos ) return // Do nothing if bot is not guarding anything
// Only look for mobs within 16 blocks
const filter = e => e . position . distanceTo ( bot . entity . position ) < 16 && filterHostileMobs ( e )
const entityEnemy = bot . nearestEntity ( filter )
if ( entityEnemy && ! filterCreeper ( entityEnemy ) ) {
// if(filterCreeper(entityEnemy))
// Start attacking
// bot.off('time', lookForMobs)
// bot.on('physicTick', lookForMobs)
bot . pvp . movements . canDig = ! ! cfg . move && cfg . move . canDig
bot . pvp . attack ( entityEnemy )
} else if ( entityEnemy ) {
bot . lookAt (
entityEnemy . position
)
cfg . quiet || bot . chat ( "AH! A creeper! They creep me out!" )
}
}
function guardSelf ( entity ) {
if ( ! cfg . guard . self || entity !== bot . entity || guardPos ) return // Do nothing
// bot.chat("")
const hurtMessages = [
"ouch!" , "oww!" , "help" , "monster!"
]
const hurtMessagesPlayer = [
"leave me alone!" , "don't hurt me!" , "bully!" , "go away!" , "stop" , "no stop" , "stop it" , "murderer!" ,
"what have i ever done to you? :(" ,
]
console . info ( bot . nearestEntity ( filterAllMobs ) )
// Only look for mobs within 5 blocks
// const filter = e => e.position.distanceTo(bot.entity.position) < 5 && filterHostileMobs(e) || filterPlayers(e) && !filterMods(e)//anarchy
const filter = e => e . position . distanceTo ( bot . entity . position ) < 5 && filterHostileMobs ( e )
const entityEnemy = bot . nearestEntity ( filter )
cfg . quiet || 0.2 < Math . random ( ) && entityEnemy && bot . chat (
// TODO use fuzzy message function
filterPlayers ( entityEnemy ) ?
hurtMessagesPlayer [ Math . floor ( Math . random ( ) * hurtMessagesPlayer . length ) ]
:
hurtMessages [ Math . floor ( Math . random ( ) * hurtMessages . length ) ]
)
if ( entityEnemy && ! filterCreeper ( entityEnemy ) ) {
// Start attacking
// bot.off('time', lookForMobs)
// bot.on('physicTick', lookForMobs)
bot . pvp . attack ( entityEnemy )
bot . pvp . movements . canDig = ! ! cfg . move && cfg . move . canDig
}
}
// bot.on('physicTick', lookForMobs)
// Listen for player commands
// bot.on('chat', (username, message) => {
// // Guard the location the player is standing
// if (message === 'guard') {
// const player = bot.players[username]
// if (!player) {
// bot.chat("I can't see you.")
// return
// }
// bot.chat('I will guard that location.')
// guardArea(player.entity.position)
// }
// // Stop guarding
// if (message === 'stop') {
// bot.chat('I will no longer guard this area.')
// stopGuarding()
// }
// })
const load = ( config ) => {
cfg = config
bot = cfg . bot
cfg . guard = {
pos : null ,
auto : true ,
self : true ,
}
guardPos = cfg . guard . pos
bot . loadPlugin ( pathfinder )
bot . loadPlugin ( pvp )
bot . on ( 'stoppedAttacking' , guardArea )
bot . on ( 'entityHurt' , guardSelf )
// bot.on("time", guardArea)
}
const unload = ( ) => {
stopGuarding ( )
bot . off ( 'time' , lookForMobs )
// bot.off('physicTick', lookForMobs)
bot . off ( 'stoppedAttacking' , guardArea )
bot . off ( 'entityHurt' , guardSelf )
// bot.off("time", guardArea)
}
module . exports = { load , unload , guardArea , guardSelf , stopGuarding }