2024-01-26 13:18:30 -06:00
|
|
|
import pf from 'mineflayer-pathfinder';
|
2024-03-06 15:22:34 -08:00
|
|
|
import * as mc from '../../utils/mcdata.js';
|
2023-08-17 00:00:57 -07:00
|
|
|
|
|
|
|
|
2024-01-25 14:16:25 -08:00
|
|
|
export function getNearestFreeSpace(bot, size=1, distance=8) {
|
|
|
|
/**
|
|
|
|
* Get the nearest empty space with solid blocks beneath it of the given size.
|
|
|
|
* @param {Bot} bot - The bot to get the nearest free space for.
|
|
|
|
* @param {number} size - The (size x size) of the space to find, default 1.
|
|
|
|
* @param {number} distance - The maximum distance to search, default 8.
|
|
|
|
* @returns {Vec3} - The south west corner position of the nearest free space.
|
|
|
|
* @example
|
|
|
|
* let position = world.getNearestFreeSpace(bot, 1, 8);
|
|
|
|
**/
|
|
|
|
let empty_pos = bot.findBlocks({
|
|
|
|
matching: (block) => {
|
|
|
|
return block && block.name == 'air';
|
|
|
|
},
|
|
|
|
maxDistance: distance,
|
|
|
|
count: 1000
|
|
|
|
});
|
|
|
|
for (let i = 0; i < empty_pos.length; i++) {
|
|
|
|
let empty = true;
|
|
|
|
for (let x = 0; x < size; x++) {
|
|
|
|
for (let z = 0; z < size; z++) {
|
|
|
|
let top = bot.blockAt(empty_pos[i].offset(x, 0, z));
|
|
|
|
let bottom = bot.blockAt(empty_pos[i].offset(x, -1, z));
|
2024-03-05 16:40:06 -08:00
|
|
|
if (!top || !top.name == 'air' || !bottom || bottom.drops.length == 0 || !bottom.diggable) {
|
2024-01-25 14:16:25 -08:00
|
|
|
empty = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2024-03-05 16:40:06 -08:00
|
|
|
if (!empty) break;
|
2024-01-25 14:16:25 -08:00
|
|
|
}
|
|
|
|
if (empty) {
|
|
|
|
return empty_pos[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-08-17 00:00:57 -07:00
|
|
|
|
|
|
|
|
2024-03-06 15:22:34 -08:00
|
|
|
export function getNearestBlocks(bot, block_types=null, distance=16, count=10000) {
|
2023-12-04 21:33:40 -06:00
|
|
|
/**
|
|
|
|
* Get a list of the nearest blocks of the given types.
|
2023-11-15 22:46:51 -06:00
|
|
|
* @param {Bot} bot - The bot to get the nearest block for.
|
2023-12-04 21:33:40 -06:00
|
|
|
* @param {string[]} block_types - The names of the blocks to search for.
|
2023-11-18 10:26:02 -08:00
|
|
|
* @param {number} distance - The maximum distance to search, default 16.
|
2024-03-06 13:18:23 -08:00
|
|
|
* @param {number} count - The maximum number of blocks to find, default 10000.
|
2023-12-04 21:33:40 -06:00
|
|
|
* @returns {Block[]} - The nearest blocks of the given type.
|
2023-11-15 22:46:51 -06:00
|
|
|
* @example
|
2023-12-04 21:33:40 -06:00
|
|
|
* let woodBlocks = world.getNearestBlocks(bot, ['oak_log', 'birch_log'], 16, 1);
|
2023-11-15 22:46:51 -06:00
|
|
|
**/
|
2024-01-27 19:17:36 -06:00
|
|
|
// if blocktypes is not a list, make it a list
|
2024-03-06 15:22:34 -08:00
|
|
|
let block_ids = [];
|
|
|
|
if (block_types === null) {
|
|
|
|
block_ids = mc.getAllBlockIds(['air']);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (!Array.isArray(block_types))
|
|
|
|
block_types = [block_types];
|
|
|
|
for(let block_type of block_types) {
|
|
|
|
block_ids.push(mc.getBlockId(block_type));
|
2024-03-06 13:18:23 -08:00
|
|
|
}
|
2023-12-04 21:33:40 -06:00
|
|
|
}
|
2024-03-06 15:22:34 -08:00
|
|
|
|
|
|
|
let positions = bot.findBlocks({matching: block_ids, maxDistance: distance, count: count});
|
|
|
|
let blocks = [];
|
|
|
|
for (let i = 0; i < positions.length; i++) {
|
|
|
|
let block = bot.blockAt(positions[i]);
|
|
|
|
let distance = positions[i].distanceTo(bot.entity.position);
|
|
|
|
blocks.push({ block: block, distance: distance });
|
|
|
|
}
|
|
|
|
blocks.sort((a, b) => a.distance - b.distance);
|
|
|
|
|
|
|
|
let res = [];
|
|
|
|
for (let i = 0; i < blocks.length; i++) {
|
|
|
|
res.push(blocks[i].block);
|
|
|
|
}
|
|
|
|
return res;
|
2023-12-04 21:33:40 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export function getNearestBlock(bot, block_type, distance=16) {
|
|
|
|
/**
|
|
|
|
* Get the nearest block of the given type.
|
|
|
|
* @param {Bot} bot - The bot to get the nearest block for.
|
|
|
|
* @param {string} block_type - The name of the block to search for.
|
|
|
|
* @param {number} distance - The maximum distance to search, default 16.
|
|
|
|
* @returns {Block} - The nearest block of the given type.
|
|
|
|
* @example
|
|
|
|
* let coalBlock = world.getNearestBlock(bot, 'coal_ore', 16);
|
|
|
|
**/
|
2024-03-06 13:18:23 -08:00
|
|
|
let blocks = getNearestBlocks(bot, block_type, distance, 1);
|
2023-12-04 21:33:40 -06:00
|
|
|
if (blocks.length > 0) {
|
|
|
|
return blocks[0];
|
2023-09-29 15:53:16 -07:00
|
|
|
}
|
2023-11-15 17:01:06 -06:00
|
|
|
return null;
|
2023-09-29 15:53:16 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-01-23 18:01:38 -06:00
|
|
|
export function getNearbyEntities(bot, maxDistance=16) {
|
2023-09-29 15:53:16 -07:00
|
|
|
let entities = [];
|
|
|
|
for (const entity of Object.values(bot.entities)) {
|
|
|
|
const distance = entity.position.distanceTo(bot.entity.position);
|
|
|
|
if (distance > maxDistance) continue;
|
2023-11-19 17:11:46 -06:00
|
|
|
entities.push({ entity: entity, distance: distance });
|
2023-09-29 15:53:16 -07:00
|
|
|
}
|
|
|
|
entities.sort((a, b) => a.distance - b.distance);
|
|
|
|
let res = [];
|
|
|
|
for (let i = 0; i < entities.length; i++) {
|
|
|
|
res.push(entities[i].entity);
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2024-01-23 18:01:38 -06:00
|
|
|
export function getNearestEntityWhere(bot, predicate, maxDistance=16) {
|
|
|
|
return bot.nearestEntity(entity => predicate(entity) && bot.entity.position.distanceTo(entity.position) < maxDistance);
|
|
|
|
}
|
|
|
|
|
2023-09-29 15:53:16 -07:00
|
|
|
|
|
|
|
export function getNearbyPlayers(bot, maxDistance) {
|
|
|
|
if (maxDistance == null) maxDistance = 16;
|
|
|
|
let players = [];
|
|
|
|
for (const entity of Object.values(bot.entities)) {
|
|
|
|
const distance = entity.position.distanceTo(bot.entity.position);
|
|
|
|
if (distance > maxDistance) continue;
|
|
|
|
if (entity.type == 'player' && entity.username != bot.username) {
|
|
|
|
players.push({ entity: entity, distance: distance });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
players.sort((a, b) => a.distance - b.distance);
|
|
|
|
let res = [];
|
|
|
|
for (let i = 0; i < players.length; i++) {
|
|
|
|
res.push(players[i].entity);
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export function getInventoryStacks(bot) {
|
|
|
|
let inventory = [];
|
2023-12-04 21:33:40 -06:00
|
|
|
for (const item of bot.inventory.items()) {
|
2023-09-29 15:53:16 -07:00
|
|
|
if (item != null) {
|
|
|
|
inventory.push(item);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return inventory;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export function getInventoryCounts(bot) {
|
2023-11-07 20:21:19 -08:00
|
|
|
/**
|
|
|
|
* Get an object representing the bot's inventory.
|
|
|
|
* @param {Bot} bot - The bot to get the inventory for.
|
|
|
|
* @returns {object} - An object with item names as keys and counts as values.
|
|
|
|
* @example
|
|
|
|
* let inventory = world.getInventoryCounts(bot);
|
|
|
|
* let oakLogCount = inventory['oak_log'];
|
|
|
|
* let hasWoodenPickaxe = inventory['wooden_pickaxe'] > 0;
|
|
|
|
**/
|
2023-09-29 15:53:16 -07:00
|
|
|
let inventory = {};
|
2024-01-23 18:01:38 -06:00
|
|
|
for (const item of bot.inventory.items()) {
|
|
|
|
if (item != null) {
|
|
|
|
if (inventory[item.name] == null) {
|
|
|
|
inventory[item.name] = 0;
|
|
|
|
}
|
|
|
|
inventory[item.name] += item.count;
|
2023-09-29 15:53:16 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return inventory;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export function getPosition(bot) {
|
2023-11-07 20:21:19 -08:00
|
|
|
/**
|
|
|
|
* Get your position in the world (Note that y is vertical).
|
|
|
|
* @param {Bot} bot - The bot to get the position for.
|
|
|
|
* @returns {Vec3} - An object with x, y, and x attributes representing the position of the bot.
|
|
|
|
* @example
|
|
|
|
* let position = world.getPosition(bot);
|
|
|
|
* let x = position.x;
|
|
|
|
**/
|
2023-09-29 15:53:16 -07:00
|
|
|
return bot.entity.position;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-01-23 18:01:38 -06:00
|
|
|
export function getNearbyEntityTypes(bot) {
|
2023-11-07 20:21:19 -08:00
|
|
|
/**
|
|
|
|
* Get a list of all nearby mob types.
|
|
|
|
* @param {Bot} bot - The bot to get nearby mobs for.
|
|
|
|
* @returns {string[]} - A list of all nearby mobs.
|
|
|
|
* @example
|
2024-01-23 18:01:38 -06:00
|
|
|
* let mobs = world.getNearbyEntityTypes(bot);
|
2023-11-07 20:21:19 -08:00
|
|
|
**/
|
2024-01-23 18:01:38 -06:00
|
|
|
let mobs = getNearbyEntities(bot, 16);
|
2023-09-29 15:53:16 -07:00
|
|
|
let found = [];
|
|
|
|
for (let i = 0; i < mobs.length; i++) {
|
2023-11-19 17:11:46 -06:00
|
|
|
if (!found.includes(mobs[i].name)) {
|
|
|
|
found.push(mobs[i].name);
|
2023-09-29 15:53:16 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return found;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export function getNearbyPlayerNames(bot) {
|
2023-11-07 20:21:19 -08:00
|
|
|
/**
|
|
|
|
* Get a list of all nearby player names.
|
|
|
|
* @param {Bot} bot - The bot to get nearby players for.
|
|
|
|
* @returns {string[]} - A list of all nearby players.
|
|
|
|
* @example
|
|
|
|
* let players = world.getNearbyPlayerNames(bot);
|
|
|
|
**/
|
2023-09-29 15:53:16 -07:00
|
|
|
let players = getNearbyPlayers(bot, 16);
|
|
|
|
let found = [];
|
|
|
|
for (let i = 0; i < players.length; i++) {
|
|
|
|
if (!found.includes(players[i].username) && players[i].username != bot.username) {
|
|
|
|
found.push(players[i].username);
|
|
|
|
}
|
2023-09-29 12:53:56 -07:00
|
|
|
}
|
|
|
|
return found;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-12-04 23:26:21 -08:00
|
|
|
export function getNearbyBlockTypes(bot, distance=16) {
|
2023-11-07 20:21:19 -08:00
|
|
|
/**
|
|
|
|
* Get a list of all nearby block names.
|
|
|
|
* @param {Bot} bot - The bot to get nearby blocks for.
|
2023-12-04 23:26:21 -08:00
|
|
|
* @param {number} distance - The maximum distance to search, default 16.
|
2023-11-07 20:21:19 -08:00
|
|
|
* @returns {string[]} - A list of all nearby blocks.
|
|
|
|
* @example
|
|
|
|
* let blocks = world.getNearbyBlockTypes(bot);
|
|
|
|
**/
|
2024-03-06 15:22:34 -08:00
|
|
|
let blocks = getNearestBlocks(bot, null, distance);
|
2023-08-17 00:00:57 -07:00
|
|
|
let found = [];
|
2023-09-29 12:53:56 -07:00
|
|
|
for (let i = 0; i < blocks.length; i++) {
|
|
|
|
if (!found.includes(blocks[i].name)) {
|
|
|
|
found.push(blocks[i].name);
|
2023-08-17 00:00:57 -07:00
|
|
|
}
|
|
|
|
}
|
2023-10-19 22:49:52 -05:00
|
|
|
return found;
|
2023-08-17 00:00:57 -07:00
|
|
|
}
|
2024-01-26 13:18:30 -06:00
|
|
|
|
|
|
|
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';
|
|
|
|
}
|
2024-01-25 13:25:36 -08:00
|
|
|
|
|
|
|
export function getBiomeName(bot) {
|
|
|
|
/**
|
|
|
|
* Get the name of the biome the bot is in.
|
|
|
|
* @param {Bot} bot - The bot to get the biome for.
|
|
|
|
* @returns {string} - The name of the biome.
|
|
|
|
* @example
|
|
|
|
* let biome = world.getBiomeName(bot);
|
|
|
|
**/
|
|
|
|
const biomeId = bot.world.getBiome(bot.entity.position);
|
2024-03-06 15:22:34 -08:00
|
|
|
return mc.getAllBiomes()[biomeId].name;
|
2024-01-25 13:25:36 -08:00
|
|
|
}
|