wip: world

This commit is contained in:
RainbowBird
2025-01-07 00:16:51 +08:00
parent ddc2665bc9
commit 18e460ae50
2 changed files with 305 additions and 0 deletions
+305
View File
@@ -0,0 +1,305 @@
import pf from 'mineflayer-pathfinder'
import * as mc from '../utils/mcdata'
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);
*/
const 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++) {
const top = bot.blockAt(empty_pos[i].offset(x, 0, z))
const bottom = bot.blockAt(empty_pos[i].offset(x, -1, z))
if (!top || !top.name == 'air' || !bottom || bottom.drops.length == 0 || !bottom.diggable) {
empty = false
break
}
}
if (!empty)
break
}
if (empty) {
return empty_pos[i]
}
}
}
export function getNearestBlocks(bot, block_types = null, distance = 16, count = 10000) {
/**
* Get a list of the nearest blocks of the given types.
* @param {Bot} bot - The bot to get the nearest block for.
* @param {string[]} block_types - The names of the blocks to search for.
* @param {number} distance - The maximum distance to search, default 16.
* @param {number} count - The maximum number of blocks to find, default 10000.
* @returns {Block[]} - The nearest blocks of the given type.
* @example
* let woodBlocks = world.getNearestBlocks(bot, ['oak_log', 'birch_log'], 16, 1);
*/
// if blocktypes is not a list, make it a list
let block_ids = []
if (block_types === null) {
block_ids = mc.getAllBlockIds(['air'])
}
else {
if (!Array.isArray(block_types))
block_types = [block_types]
for (const block_type of block_types) {
block_ids.push(mc.getBlockId(block_type))
}
}
const positions = bot.findBlocks({ matching: block_ids, maxDistance: distance, count })
const blocks = []
for (let i = 0; i < positions.length; i++) {
const block = bot.blockAt(positions[i])
const distance = positions[i].distanceTo(bot.entity.position)
blocks.push({ block, distance })
}
blocks.sort((a, b) => a.distance - b.distance)
const res = []
for (let i = 0; i < blocks.length; i++) {
res.push(blocks[i].block)
}
return res
}
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);
*/
const blocks = getNearestBlocks(bot, block_type, distance, 1)
if (blocks.length > 0) {
return blocks[0]
}
return null
}
export function getNearbyEntities(bot, maxDistance = 16) {
const entities = []
for (const entity of Object.values(bot.entities)) {
const distance = entity.position.distanceTo(bot.entity.position)
if (distance > maxDistance)
continue
entities.push({ entity, distance })
}
entities.sort((a, b) => a.distance - b.distance)
const res = []
for (let i = 0; i < entities.length; i++) {
res.push(entities[i].entity)
}
return res
}
export function getNearestEntityWhere(bot, predicate, maxDistance = 16) {
return bot.nearestEntity(entity => predicate(entity) && bot.entity.position.distanceTo(entity.position) < maxDistance)
}
export function getNearbyPlayers(bot, maxDistance) {
if (maxDistance == null)
maxDistance = 16
const 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, distance })
}
}
players.sort((a, b) => a.distance - b.distance)
const res = []
for (let i = 0; i < players.length; i++) {
res.push(players[i].entity)
}
return res
}
export function getInventoryStacks(bot) {
const inventory = []
for (const item of bot.inventory.items()) {
if (item != null) {
inventory.push(item)
}
}
return inventory
}
export function getInventoryCounts(bot) {
/**
* 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;
*/
const inventory = {}
for (const item of bot.inventory.items()) {
if (item != null) {
if (inventory[item.name] == null) {
inventory[item.name] = 0
}
inventory[item.name] += item.count
}
}
return inventory
}
export function getCraftableItems(bot) {
/**
* Get a list of all items that can be crafted with the bot's current inventory.
* @param {Bot} bot - The bot to get the craftable items for.
* @returns {string[]} - A list of all items that can be crafted.
* @example
* let craftableItems = world.getCraftableItems(bot);
*/
let table = getNearestBlock(bot, 'crafting_table')
if (!table) {
for (const item of bot.inventory.items()) {
if (item != null && item.name === 'crafting_table') {
table = item
break
}
}
}
const res = []
for (const item of mc.getAllItems()) {
const recipes = bot.recipesFor(item.id, null, 1, table)
if (recipes.length > 0)
res.push(item.name)
}
return res
}
export function getPosition(bot) {
/**
* 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;
*/
return bot.entity.position
}
export function getNearbyEntityTypes(bot) {
/**
* 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
* let mobs = world.getNearbyEntityTypes(bot);
*/
const mobs = getNearbyEntities(bot, 16)
const found = []
for (let i = 0; i < mobs.length; i++) {
if (!found.includes(mobs[i].name)) {
found.push(mobs[i].name)
}
}
return found
}
export function getNearbyPlayerNames(bot) {
/**
* 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);
*/
const players = getNearbyPlayers(bot, 64)
const 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)
}
}
return found
}
export function getNearbyBlockTypes(bot, distance = 16) {
/**
* Get a list of all nearby block names.
* @param {Bot} bot - The bot to get nearby blocks for.
* @param {number} distance - The maximum distance to search, default 16.
* @returns {string[]} - A list of all nearby blocks.
* @example
* let blocks = world.getNearbyBlockTypes(bot);
*/
const blocks = getNearestBlocks(bot, null, distance)
const found = []
for (let i = 0; i < blocks.length; i++) {
if (!found.includes(blocks[i].name)) {
found.push(blocks[i].name)
}
}
return found
}
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.
*/
const movements = new pf.Movements(bot)
movements.canDig = false
movements.canPlaceOn = false
const goal = new pf.goals.GoalNear(target.position.x, target.position.y, target.position.z, 1)
const path = await bot.pathfinder.getPathTo(movements, goal, 100)
return path.status === 'success'
}
export function shouldPlaceTorch(bot) {
if (!bot.modes.isOn('torch_placing') || bot.interrupt_code)
return false
const pos = getPosition(bot)
// TODO: check light level instead of nearby torches, block.light is broken
let nearest_torch = getNearestBlock(bot, 'torch', 6)
if (!nearest_torch)
nearest_torch = getNearestBlock(bot, 'wall_torch', 6)
if (!nearest_torch) {
const block = bot.blockAt(pos)
const has_torch = bot.inventory.items().find(item => item.name === 'torch')
return has_torch && block?.name === 'air'
}
return false
}
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)
return mc.getAllBiomes()[biomeId].name
}