You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
370 lines
12 KiB
370 lines
12 KiB
|
|
const { Movements } = require('mineflayer-pathfinder') |
|
const v = require('vec3') |
|
|
|
let cfg = {} |
|
let bot = {} |
|
// let moving |
|
let pathfinder |
|
let mcData |
|
let movements = [] |
|
|
|
|
|
function initMoves(bot = bot, mcData = bot.mcData) { |
|
if (movements.length > 0) { |
|
bot.pathfinder.setMovements(movements.defaultMove) |
|
return console.warn("go init: movements already initialized!", movements) |
|
} |
|
const normalMove = new Movements(bot, mcData) |
|
normalMove.canDig = false |
|
normalMove.scafoldingBlocks.push(mcData.blocksByName.slime_block.id) |
|
normalMove.blocksCantBreak.add(mcData.blocksByName.glass.id) |
|
normalMove.blocksToAvoid.add(mcData.blocksByName.magma_block.id) |
|
movements.push(normalMove) |
|
movements.defaultMove = movements[0] |
|
|
|
bot.pathfinder.setMovements(normalMove) |
|
} |
|
|
|
|
|
function moveNear(pos, distance = 3) { |
|
const { GoalNear } = require('mineflayer-pathfinder').goals |
|
|
|
pos = v(pos) |
|
cfg.quiet || bot.chat(`moving to ${pos.floored()}`) |
|
bot.pathfinder.setMovements(movements.defaultMove) |
|
bot.pathfinder.setGoal(new GoalNear(pos.x, pos.y, pos.z, distance)) |
|
} |
|
|
|
function moveXZ(pos) { |
|
const { GoalXZ } = require('mineflayer-pathfinder').goals |
|
|
|
if (Array.isArray(pos) && pos.length == 2) { |
|
pos = v(pos[0], 0, pos[1]) |
|
} |
|
pos = v(pos) |
|
console.log(pos) |
|
cfg.quiet || bot.chat(`moving to ${pos.floored()}`) |
|
bot.pathfinder.setMovements(movements.defaultMove) |
|
bot.pathfinder.setGoal(new GoalXZ(pos.x, pos.z)) |
|
} |
|
|
|
function moveY(pos) { |
|
const { GoalY } = require('mineflayer-pathfinder').goals |
|
|
|
if (Array.isArray(pos) && pos.length == 1) { |
|
pos = v(null, pos[0], null) |
|
} |
|
pos = v(pos) |
|
console.log(pos) |
|
cfg.quiet || bot.chat(`moving to ${pos.floored()}`) |
|
bot.pathfinder.setMovements(movements.defaultMove) |
|
bot.pathfinder.setGoal(new GoalY(pos.y)) |
|
} |
|
|
|
function follow(entity, dynamic = true, distance = 3) { |
|
console.assert(entity) |
|
const { GoalFollow } = require('mineflayer-pathfinder').goals |
|
|
|
// console.log(entity) |
|
cfg.quiet || bot.chat( |
|
`following ${entity.type |
|
}: ${entity.username || entity.displayName |
|
}${dynamic ? "" : " once"}` |
|
) |
|
|
|
entity = entity.entity ? entity.entity : entity |
|
|
|
// console.log(entity) |
|
|
|
bot.pathfinder.setMovements(movements.defaultMove) |
|
bot.pathfinder.setGoal(new GoalFollow(entity, distance), dynamic) |
|
} |
|
|
|
function away(entity = bot.nearestEntity(), invertInvert = true, dynamic = true, distance = 10) { |
|
const currentGoal = bot.pathfinder.goal |
|
console.assert(currentGoal || entity) |
|
const { GoalInvert } = require('mineflayer-pathfinder').goals |
|
|
|
bot.pathfinder.setMovements(movements.defaultMove) |
|
|
|
if (!currentGoal) { |
|
const { GoalFollow } = require('mineflayer-pathfinder').goals |
|
|
|
if (entity.entity) { |
|
console.log("go away entity:", entity, entity.entity) |
|
entity = entity.entity |
|
} |
|
|
|
cfg.quiet || bot.chat( |
|
`going away from ${entity?.type |
|
}: ${entity?.username || entity?.displayName |
|
}${dynamic ? "" : " once"}` |
|
) |
|
// alternative implementation |
|
// follow(entity, dynamic, distance) |
|
// bot.pathfinder.setGoal(new GoalInvert(bot.pathfinder.goal), dynamic) |
|
return bot.pathfinder.setGoal(new GoalInvert( |
|
new GoalFollow(entity, distance) |
|
), dynamic) |
|
} |
|
|
|
if (currentGoal instanceof GoalInvert) { |
|
const currEntity = currentGoal.goal.entity |
|
console.log("go away inverse goal:", currentGoal.goal) |
|
if (invertInvert) { |
|
cfg.quiet || bot.chat( |
|
`switching towards ${currentGoal.goal?.constructor.name |
|
}: ${currEntity?.type |
|
}: ${currEntity?.username || currEntity?.displayName |
|
}${dynamic ? "" : " once"}` |
|
) |
|
bot.pathfinder.setGoal(currentGoal.goal, dynamic) |
|
} else { |
|
cfg.quiet || bot.chat( |
|
`already going away from ${currentGoal.goal?.constructor.name |
|
}; not switching` |
|
) |
|
} |
|
} else { |
|
const currEntity = currentGoal.entity |
|
console.log("go away goal:", currentGoal) |
|
cfg.quiet || bot.chat( |
|
`going away from ${currentGoal?.constructor.name |
|
}: ${currEntity?.type |
|
}: ${currEntity?.username || currEntity?.displayName |
|
}${dynamic ? "" : " once"}` |
|
) |
|
bot.pathfinder.setGoal(new GoalInvert(currentGoal), dynamic) |
|
} |
|
|
|
|
|
} |
|
|
|
function ride(entity) { |
|
entity = entity?.entity || entity |
|
const ridableMobs = ["Horse", "Donkey", "Pig", "Strider", "Mule"] |
|
const vehicle = entity && typeof entity !== "string" ? entity : bot.nearestEntity(e => { |
|
if (typeof entity === "string") return e.name === entity |
|
const maybeRidableMob = e.mobType?.split(" ") |
|
return e.kind == "Vehicles" |
|
|| ridableMobs.includes(e.mobType) |
|
|| maybeRidableMob && ridableMobs.includes(maybeRidableMob[maybeRidableMob.length - 1]) |
|
}) |
|
if (!vehicle) { |
|
return cfg.quiet || bot.chat(`nothing to ride!`) |
|
} else if ((dist = bot.entity.position.distanceSquared(vehicle.position)) > 36) { |
|
bot.lookAt(vehicle.position) |
|
follow(vehicle, false) |
|
bot.once('goal_reached', ride) |
|
return cfg.quiet || bot.chat(`${vehicle.name} bit far`) |
|
} |
|
console.log("vehicle:", vehicle) |
|
bot.mount(vehicle) |
|
} |
|
|
|
function moveOrRide(turn = false, reverse = -1, directionLabel, message_parts2) { |
|
// bot.once("attach", state = "vehiccel") |
|
if (bot.vehicle) { |
|
// FIXME moveVehicle should be +-1 or 0? |
|
const amount = parseInt(message_parts2[0]) * -reverse |
|
bot.moveVehicle(turn && Math.sign(amount) || 0, !turn && amount || 0) |
|
} else { |
|
command([directionLabel].concat(message_parts2)) |
|
} |
|
} |
|
|
|
function hit(blockOrEntity) { |
|
bot.chat(`hitting ${entity.name || entity.type}`) |
|
} |
|
|
|
function goalReached(goal) { |
|
console.log(goal) |
|
const entity = goal?.entity |
|
let entityInfo = "" |
|
if (entity) { |
|
entityInfo += entity.type + ": " |
|
switch (entity.type) { |
|
case "player": |
|
entityInfo += entity.username |
|
break; |
|
default: |
|
break; |
|
} |
|
} |
|
cfg.quiet || bot.chat(`goal reached: ${entityInfo}; pos: [x:${goal?.x}, y:${goal?.y}, z:${goal?.z}]`) |
|
} |
|
|
|
function stop() { |
|
bot.pathfinder.setGoal(null) |
|
bot.stopDigging() |
|
} |
|
|
|
function command(message_parts, player) { |
|
const message_parts2 = message_parts.slice(1) |
|
switch (message_parts[0]) { |
|
case "init": |
|
initMoves() |
|
break |
|
case "near": |
|
switch (message_parts2.length) { |
|
case 0: |
|
moveNear(bot.nearestEntity().position) |
|
break |
|
case 1: |
|
switch (message_parts2[0]) { |
|
case "me": |
|
if (player) { |
|
moveNear(player.position) |
|
} else { |
|
cfg.quiet || bot.chat("can't see you") |
|
} |
|
break; |
|
|
|
default: |
|
const aPlayer = bot.players[message_parts2[0]] ? bot.players[message_parts2[0]].entity : null |
|
if (aPlayer) { |
|
moveNear(aPlayer.position) |
|
} else { |
|
cfg.quiet || bot.chat(`can't see ${message_parts2[0]}`) |
|
} |
|
break; |
|
} |
|
break |
|
case 2: |
|
//TODO this isn't near |
|
moveXZ(message_parts2) |
|
break |
|
case 3: |
|
//TODO more checks |
|
moveNear(message_parts2) |
|
break |
|
default: |
|
break |
|
} |
|
break |
|
|
|
case "follow": |
|
// message_parts2 = message_parts.slice(2) |
|
switch (message_parts2.length) { |
|
case 0: |
|
follow(bot.nearestEntity()) |
|
break |
|
case 1: |
|
let dist = 3 |
|
switch (message_parts2[0]) { |
|
case "close": |
|
dist = 1 |
|
case "me": |
|
case "once": |
|
if (player) { |
|
follow(player, message_parts2[0] === "me", dist) |
|
} else { |
|
cfg.quiet || bot.chat("can't see you") |
|
} |
|
break; |
|
|
|
default: |
|
const aPlayer = bot.players[message_parts2[0]] ? bot.players[message_parts2[0]].entity : null |
|
if (aPlayer) { |
|
follow(aPlayer) |
|
} else { |
|
cfg.quiet || bot.chat(`can't see ${message_parts2[0]}`) |
|
} |
|
break; |
|
} |
|
break |
|
// case 2: |
|
// bot.lookAt({}) goalxz? |
|
// break |
|
// case 3: |
|
//TODO more checks |
|
// moveNear(message_parts2) |
|
// break |
|
default: |
|
cfg.quiet || bot.chat("unknown or bad command") |
|
break |
|
} |
|
break |
|
case "ride": |
|
case "mount": |
|
ride(message_parts2[0]) |
|
break |
|
case "away": |
|
case "run": |
|
case "runaway": |
|
away() |
|
break |
|
case "w": |
|
case "f": |
|
moveOrRide(0, -1, "forward", message_parts2) |
|
break |
|
case "s": |
|
case "b": |
|
moveOrRide(0, 1, "back", message_parts2) |
|
break |
|
case "a": |
|
case "l": |
|
moveOrRide(1, -1, "right", message_parts2) |
|
break |
|
case "d": |
|
case "r": |
|
moveOrRide(1, 1, "left", message_parts2) |
|
break |
|
case "up": |
|
case "u": |
|
case "j": |
|
moveOrRide(1, 1, "left", message_parts2) |
|
break |
|
case "back": |
|
case "forward": |
|
case "jump": |
|
case "left": |
|
case "right": |
|
case "sneak": |
|
case "sprint": |
|
console.info(bot.controlState[message_parts[0]], bot.entity.position.floored()) |
|
bot.setControlState(message_parts[0], true) |
|
console.info(bot.controlState[message_parts[0]]) |
|
setTimeout(bot.setControlState, 100 * (message_parts[1] || 2), message_parts[0], false) |
|
setTimeout(console.info, 5000, bot.controlState[message_parts[0]], bot.entity.position.floored()) |
|
break |
|
case "stop": |
|
stop() |
|
break |
|
default: |
|
return cfg.quiet || bot.chat(`unknown command ${message_parts[0]}`) |
|
} |
|
} |
|
|
|
const load = (config) => { |
|
cfg = config |
|
bot = cfg.bot |
|
cfg.move = { |
|
// auto: true, |
|
canDig: false, |
|
// list: ["hello", "wassup"], |
|
quiet: !!cfg.quiet, |
|
movements: [] |
|
} |
|
|
|
mcData = bot.mcData || (bot.mcData = require('minecraft-data')(bot.version)) |
|
pathfinder = bot.pathfinder || bot.loadPlugin(require('mineflayer-pathfinder').pathfinder) |
|
|
|
// initMoves(bot, mcData) |
|
setTimeout(initMoves, 500, bot, mcData) |
|
bot.on('goal_reached', goalReached) |
|
|
|
} |
|
|
|
const unload = () => { |
|
stop() |
|
bot.off('goal_reached', goalReached) |
|
} |
|
|
|
module.exports = { |
|
load, unload, command, |
|
stop, initMoves, |
|
moveNear, moveXZ, moveY, follow, |
|
ride |
|
} |