2024-01-25 13:25:36 -08:00
import * as mc from "../../utils/mcdata.js" ;
import * as world from "./world.js" ;
2023-08-15 23:39:02 -07:00
import pf from 'mineflayer-pathfinder' ;
2023-11-08 19:24:24 -06:00
import Vec3 from 'vec3' ;
2023-08-15 23:39:02 -07:00
2024-01-25 13:25:36 -08:00
2024-12-01 22:28:21 -06:00
export function log ( bot , message ) {
2023-11-12 13:57:22 -06:00
bot . output += message + '\n' ;
}
2024-01-25 13:25:36 -08:00
async function autoLight ( bot ) {
2024-06-03 19:09:22 -05:00
if ( world . shouldPlaceTorch ( bot ) ) {
2024-06-03 18:23:01 -05:00
try {
const pos = world . getPosition ( bot ) ;
2024-06-22 15:19:10 -05:00
return await placeBlock ( bot , 'torch' , pos . x , pos . y , pos . z , 'bottom' , true ) ;
2024-06-03 18:23:01 -05:00
} catch ( err ) { return false ; }
2024-01-25 13:25:36 -08:00
}
return false ;
}
2024-02-05 19:08:08 -06:00
async function equipHighestAttack ( bot ) {
let weapons = bot . inventory . items ( ) . filter ( item => item . name . includes ( 'sword' ) || ( item . name . includes ( 'axe' ) && ! item . name . includes ( 'pickaxe' ) ) ) ;
if ( weapons . length === 0 )
weapons = bot . inventory . items ( ) . filter ( item => item . name . includes ( 'pickaxe' ) || item . name . includes ( 'shovel' ) ) ;
if ( weapons . length === 0 )
return ;
weapons . sort ( ( a , b ) => a . attackDamage < b . attackDamage ) ;
let weapon = weapons [ 0 ] ;
2024-01-25 13:25:36 -08:00
if ( weapon )
2024-02-05 19:08:08 -06:00
await bot . equip ( weapon , 'hand' ) ;
2024-01-25 13:25:36 -08:00
}
2024-03-05 12:50:13 -08:00
export async function craftRecipe ( bot , itemName , num = 1 ) {
2023-11-07 09:44:56 -06:00
/ * *
2023-11-27 21:07:52 -06:00
* Attempt to craft the given item name from a recipe . May craft many items .
2023-11-07 09:44:56 -06:00
* @ param { MinecraftBot } bot , reference to the minecraft bot .
2023-11-27 21:07:52 -06:00
* @ param { string } itemName , the item name to craft .
2024-01-16 15:53:27 -06:00
* @ returns { Promise < boolean > } true if the recipe was crafted , false otherwise .
2023-11-07 09:44:56 -06:00
* @ example
2023-11-27 21:07:52 -06:00
* await skills . craftRecipe ( bot , "stick" ) ;
2023-11-07 09:44:56 -06:00
* * /
2024-01-25 14:16:25 -08:00
let placedTable = false ;
2024-10-30 13:33:25 -04:00
if ( mc . getItemCraftingRecipes ( itemName ) . length == 0 ) {
log ( bot , ` ${ itemName } is either not an item, or it does not have a crafting recipe! ` ) ;
return false ;
}
2024-01-25 14:16:25 -08:00
// get recipes that don't require a crafting table
let recipes = bot . recipesFor ( mc . getItemId ( itemName ) , null , 1 , null ) ;
2023-12-04 21:33:40 -06:00
let craftingTable = null ;
2024-08-22 15:57:20 -05:00
const craftingTableRange = 32 ;
2024-09-26 16:29:39 +10:00
placeTable : if ( ! recipes || recipes . length === 0 ) {
recipes = bot . recipesFor ( mc . getItemId ( itemName ) , null , 1 , true ) ;
if ( ! recipes || recipes . length === 0 ) break placeTable ; //Don't bother going to the table if we don't have the required resources.
2024-01-25 14:16:25 -08:00
// Look for crafting table
2024-08-22 15:57:20 -05:00
craftingTable = world . getNearestBlock ( bot , 'crafting_table' , craftingTableRange ) ;
2023-11-15 17:01:23 -06:00
if ( craftingTable === null ) {
2024-01-25 14:16:25 -08:00
// Try to place crafting table
let hasTable = world . getInventoryCounts ( bot ) [ 'crafting_table' ] > 0 ;
if ( hasTable ) {
let pos = world . getNearestFreeSpace ( bot , 1 , 6 ) ;
await placeBlock ( bot , 'crafting_table' , pos . x , pos . y , pos . z ) ;
2024-08-22 15:57:20 -05:00
craftingTable = world . getNearestBlock ( bot , 'crafting_table' , craftingTableRange ) ;
2024-01-25 14:16:25 -08:00
if ( craftingTable ) {
recipes = bot . recipesFor ( mc . getItemId ( itemName ) , null , 1 , craftingTable ) ;
placedTable = true ;
}
}
else {
2024-09-26 16:29:39 +10:00
log ( bot , ` Crafting ${ itemName } requires a crafting table. ` )
2024-01-25 14:16:25 -08:00
return false ;
}
}
else {
recipes = bot . recipesFor ( mc . getItemId ( itemName ) , null , 1 , craftingTable ) ;
2023-11-15 17:01:23 -06:00
}
}
if ( ! recipes || recipes . length === 0 ) {
2024-10-30 13:33:25 -04:00
log ( bot , ` You do not have the resources to craft a ${ itemName } . It requires: ${ Object . entries ( mc . getItemCraftingRecipes ( itemName ) [ 0 ] ) . map ( ( [ key , value ] ) => ` ${ key } : ${ value } ` ) . join ( ', ' ) } . ` ) ;
2024-01-25 14:16:25 -08:00
if ( placedTable ) {
await collectBlock ( bot , 'crafting_table' , 1 ) ;
}
2023-11-15 17:01:23 -06:00
return false ;
}
2024-08-22 15:57:20 -05:00
if ( craftingTable && bot . entity . position . distanceTo ( craftingTable . position ) > 4 ) {
await goToNearestBlock ( bot , 'crafting_table' , 4 , craftingTableRange ) ;
}
2023-11-15 17:01:23 -06:00
2024-01-25 14:16:25 -08:00
const recipe = recipes [ 0 ] ;
2023-11-15 17:01:23 -06:00
console . log ( 'crafting...' ) ;
2024-09-25 11:43:31 +10:00
//Check that the agent has sufficient items to use the recipe `num` times.
2024-09-26 16:29:39 +10:00
const inventory = world . getInventoryCounts ( bot ) ; //Items in the agents inventory
2024-10-14 07:32:39 +10:00
const requiredIngredients = mc . ingredientsFromPrismarineRecipe ( recipe ) ; //Items required to use the recipe once.
const craftLimit = mc . calculateLimitingResource ( inventory , requiredIngredients ) ;
2024-09-26 16:29:39 +10:00
await bot . craft ( recipe , Math . min ( craftLimit . num , num ) , craftingTable ) ;
if ( craftLimit . num < num ) log ( bot , ` Not enough ${ craftLimit . limitingResource } to craft ${ num } , crafted ${ craftLimit . num } . You now have ${ world . getInventoryCounts ( bot ) [ itemName ] } ${ itemName } . ` ) ;
2024-09-25 11:43:31 +10:00
else log ( bot , ` Successfully crafted ${ itemName } , you now have ${ world . getInventoryCounts ( bot ) [ itemName ] } ${ itemName } . ` ) ;
2024-01-25 14:16:25 -08:00
if ( placedTable ) {
await collectBlock ( bot , 'crafting_table' , 1 ) ;
}
2024-09-25 11:44:21 +10:00
//Equip any armor the bot may have crafted.
//There is probablly a more efficient method than checking the entire inventory but this is all mineflayer-armor-manager provides. :P
bot . armorManager . equipAll ( ) ;
2023-08-15 23:39:02 -07:00
return true ;
}
2023-12-04 21:33:40 -06:00
export async function smeltItem ( bot , itemName , num = 1 ) {
/ * *
* Puts 1 coal in furnace and smelts the given item name , waits until the furnace runs out of fuel or input items .
* @ param { MinecraftBot } bot , reference to the minecraft bot .
2024-01-13 12:11:04 -06:00
* @ param { string } itemName , the item name to smelt . Ores must contain "raw" like raw _iron .
2023-12-04 21:33:40 -06:00
* @ param { number } num , the number of items to smelt . Defaults to 1.
* @ returns { Promise < boolean > } true if the item was smelted , false otherwise . Fail
* @ example
* await skills . smeltItem ( bot , "raw_iron" ) ;
2024-01-13 12:11:04 -06:00
* await skills . smeltItem ( bot , "beef" ) ;
2023-12-04 21:33:40 -06:00
* * /
2024-10-18 10:46:35 -05:00
if ( ! mc . isSmeltable ( itemName ) ) {
log ( bot , ` Cannot smelt ${ itemName } . Hint: make sure you are smelting the 'raw' item. ` ) ;
2023-12-04 22:33:30 -06:00
return false ;
2024-10-18 10:46:35 -05:00
}
2023-12-04 22:33:30 -06:00
2024-03-05 12:50:13 -08:00
let placedFurnace = false ;
2023-12-04 21:33:40 -06:00
let furnaceBlock = undefined ;
2024-08-22 15:57:20 -05:00
const furnaceRange = 32 ;
furnaceBlock = world . getNearestBlock ( bot , 'furnace' , furnaceRange ) ;
2023-12-10 20:19:07 -06:00
if ( ! furnaceBlock ) {
2024-03-05 12:50:13 -08:00
// Try to place furnace
let hasFurnace = world . getInventoryCounts ( bot ) [ 'furnace' ] > 0 ;
if ( hasFurnace ) {
2024-08-22 15:57:20 -05:00
let pos = world . getNearestFreeSpace ( bot , 1 , furnaceRange ) ;
2024-03-05 12:50:13 -08:00
await placeBlock ( bot , 'furnace' , pos . x , pos . y , pos . z ) ;
2024-08-22 15:57:20 -05:00
furnaceBlock = world . getNearestBlock ( bot , 'furnace' , furnaceRange ) ;
2024-03-05 12:50:13 -08:00
placedFurnace = true ;
}
}
if ( ! furnaceBlock ) {
log ( bot , ` There is no furnace nearby and you have no furnace. ` )
2023-12-04 21:33:40 -06:00
return false ;
}
2024-08-22 15:57:20 -05:00
if ( bot . entity . position . distanceTo ( furnaceBlock . position ) > 4 ) {
await goToNearestBlock ( bot , 'furnace' , 4 , furnaceRange ) ;
}
2024-10-10 22:17:39 -05:00
bot . modes . pause ( 'unstuck' ) ;
2023-12-04 21:33:40 -06:00
await bot . lookAt ( furnaceBlock . position ) ;
console . log ( 'smelting...' ) ;
const furnace = await bot . openFurnace ( furnaceBlock ) ;
// check if the furnace is already smelting something
let input _item = furnace . inputItem ( ) ;
2024-01-25 13:25:36 -08:00
if ( input _item && input _item . type !== mc . getItemId ( itemName ) && input _item . count > 0 ) {
2023-12-04 21:33:40 -06:00
// TODO: check if furnace is currently burning fuel. furnace.fuel is always null, I think there is a bug.
// This only checks if the furnace has an input item, but it may not be smelting it and should be cleared.
2024-01-25 13:25:36 -08:00
log ( bot , ` The furnace is currently smelting ${ mc . getItemName ( input _item . type ) } . ` ) ;
2024-03-05 12:50:13 -08:00
if ( placedFurnace )
await collectBlock ( bot , 'furnace' , 1 ) ;
2023-12-04 21:33:40 -06:00
return false ;
}
// check if the bot has enough items to smelt
2024-01-25 13:25:36 -08:00
let inv _counts = world . getInventoryCounts ( bot ) ;
2023-12-04 21:33:40 -06:00
if ( ! inv _counts [ itemName ] || inv _counts [ itemName ] < num ) {
log ( bot , ` You do not have enough ${ itemName } to smelt. ` ) ;
2024-03-05 12:50:13 -08:00
if ( placedFurnace )
await collectBlock ( bot , 'furnace' , 1 ) ;
2023-12-04 21:33:40 -06:00
return false ;
}
// fuel the furnace
if ( ! furnace . fuelItem ( ) ) {
2024-10-18 10:46:35 -05:00
let fuel = mc . getSmeltingFuel ( bot ) ;
if ( ! fuel ) {
2024-10-20 13:03:15 -05:00
log ( bot , ` You have no fuel to smelt ${ itemName } , you need coal, charcoal, or wood. ` ) ;
2024-10-18 10:46:35 -05:00
if ( placedFurnace )
await collectBlock ( bot , 'furnace' , 1 ) ;
return false ;
}
log ( bot , ` Using ${ fuel . name } as fuel. ` ) ;
const put _fuel = Math . ceil ( num / mc . getFuelSmeltOutput ( fuel . name ) ) ;
if ( fuel . count < put _fuel ) {
log ( bot , ` You don't have enough ${ fuel . name } to smelt ${ num } ${ itemName } ; you need ${ put _fuel } . ` ) ;
2024-03-05 12:50:13 -08:00
if ( placedFurnace )
await collectBlock ( bot , 'furnace' , 1 ) ;
2023-12-04 21:33:40 -06:00
return false ;
}
await furnace . putFuel ( fuel . type , null , put _fuel ) ;
2024-01-25 13:25:36 -08:00
log ( bot , ` Added ${ put _fuel } ${ mc . getItemName ( fuel . type ) } to furnace fuel. ` ) ;
console . log ( ` Added ${ put _fuel } ${ mc . getItemName ( fuel . type ) } to furnace fuel. ` )
2023-12-04 21:33:40 -06:00
}
// put the items in the furnace
2024-01-25 13:25:36 -08:00
await furnace . putInput ( mc . getItemId ( itemName ) , null , num ) ;
2023-12-04 21:33:40 -06:00
// wait for the items to smelt
let total = 0 ;
let collected _last = true ;
let smelted _item = null ;
2023-12-04 22:33:30 -06:00
await new Promise ( resolve => setTimeout ( resolve , 200 ) ) ;
2023-12-04 21:33:40 -06:00
while ( total < num ) {
await new Promise ( resolve => setTimeout ( resolve , 10000 ) ) ;
console . log ( 'checking...' ) ;
let collected = false ;
if ( furnace . outputItem ( ) ) {
smelted _item = await furnace . takeOutput ( ) ;
if ( smelted _item ) {
total += smelted _item . count ;
collected = true ;
}
}
if ( ! collected && ! collected _last ) {
break ; // if nothing was collected this time or last time
}
collected _last = collected ;
if ( bot . interrupt _code ) {
break ;
}
}
2024-09-27 17:03:00 -05:00
await bot . closeWindow ( furnace ) ;
2023-12-04 21:33:40 -06:00
2024-03-05 12:50:13 -08:00
if ( placedFurnace ) {
await collectBlock ( bot , 'furnace' , 1 ) ;
}
2023-12-04 21:33:40 -06:00
if ( total === 0 ) {
log ( bot , ` Failed to smelt ${ itemName } . ` ) ;
return false ;
}
if ( total < num ) {
2024-01-25 13:25:36 -08:00
log ( bot , ` Only smelted ${ total } ${ mc . getItemName ( smelted _item . type ) } . ` ) ;
2023-12-04 21:33:40 -06:00
return false ;
}
2024-01-25 13:25:36 -08:00
log ( bot , ` Successfully smelted ${ itemName } , got ${ total } ${ mc . getItemName ( smelted _item . type ) } . ` ) ;
2023-12-04 21:33:40 -06:00
return true ;
}
export async function clearNearestFurnace ( bot ) {
/ * *
* Clears the nearest furnace of all items .
* @ param { MinecraftBot } bot , reference to the minecraft bot .
* @ returns { Promise < boolean > } true if the furnace was cleared , false otherwise .
* @ example
* await skills . clearNearestFurnace ( bot ) ;
* * /
2024-10-10 20:04:02 -05:00
let furnaceBlock = world . getNearestBlock ( bot , 'furnace' , 32 ) ;
if ( ! furnaceBlock ) {
log ( bot , ` No furnace nearby to clear. ` ) ;
2023-12-04 21:33:40 -06:00
return false ;
}
2024-10-10 20:04:02 -05:00
if ( bot . entity . position . distanceTo ( furnaceBlock . position ) > 4 ) {
await goToNearestBlock ( bot , 'furnace' , 4 , 32 ) ;
}
2023-12-04 21:33:40 -06:00
console . log ( 'clearing furnace...' ) ;
const furnace = await bot . openFurnace ( furnaceBlock ) ;
console . log ( 'opened furnace...' )
// take the items out of the furnace
let smelted _item , intput _item , fuel _item ;
if ( furnace . outputItem ( ) )
smelted _item = await furnace . takeOutput ( ) ;
if ( furnace . inputItem ( ) )
intput _item = await furnace . takeInput ( ) ;
if ( furnace . fuelItem ( ) )
fuel _item = await furnace . takeFuel ( ) ;
console . log ( smelted _item , intput _item , fuel _item )
let smelted _name = smelted _item ? ` ${ smelted _item . count } ${ smelted _item . name } ` : ` 0 smelted items ` ;
let input _name = intput _item ? ` ${ intput _item . count } ${ intput _item . name } ` : ` 0 input items ` ;
let fuel _name = fuel _item ? ` ${ fuel _item . count } ${ fuel _item . name } ` : ` 0 fuel items ` ;
2024-10-20 16:29:56 +09:00
log ( bot , ` Cleared furnace, received ${ smelted _name } , ${ input _name } , and ${ fuel _name } . ` ) ;
2023-12-04 21:33:40 -06:00
return true ;
}
2024-01-23 18:01:38 -06:00
export async function attackNearest ( bot , mobType , kill = true ) {
2023-11-07 09:44:56 -06:00
/ * *
* Attack mob of the given type .
* @ param { MinecraftBot } bot , reference to the minecraft bot .
* @ param { string } mobType , the type of mob to attack .
2023-11-19 17:11:46 -06:00
* @ param { boolean } kill , whether or not to continue attacking until the mob is dead . Defaults to true .
2023-11-07 09:44:56 -06:00
* @ returns { Promise < boolean > } true if the mob was attacked , false if the mob type was not found .
* @ example
2024-01-24 17:24:52 -06:00
* await skills . attackNearest ( bot , "zombie" , true ) ;
2023-11-07 09:44:56 -06:00
* * /
2024-04-13 22:56:18 -05:00
bot . modes . pause ( 'cowardice' ) ;
2024-10-12 20:40:16 -05:00
if ( mobType === 'drowned' || mobType === 'cod' || mobType === 'salmon' || mobType === 'tropical_fish' || mobType === 'squid' )
bot . modes . pause ( 'self_preservation' ) ; // so it can go underwater. TODO: have an drowning mode so we don't turn off all self_preservation
2024-04-20 22:22:26 -05:00
const mob = world . getNearbyEntities ( bot , 24 ) . find ( entity => entity . name === mobType ) ;
2024-01-13 12:11:04 -06:00
if ( mob ) {
2024-01-23 18:01:38 -06:00
return await attackEntity ( bot , mob , kill ) ;
}
log ( bot , 'Could not find any ' + mobType + ' to attack.' ) ;
return false ;
}
export async function attackEntity ( bot , entity , kill = true ) {
/ * *
* Attack mob of the given type .
* @ param { MinecraftBot } bot , reference to the minecraft bot .
* @ param { Entity } entity , the entity to attack .
* @ returns { Promise < boolean > } true if the entity was attacked , false if interrupted
* @ example
* await skills . attackEntity ( bot , entity ) ;
* * /
2023-11-19 17:11:46 -06:00
2024-01-23 18:01:38 -06:00
let pos = entity . position ;
2024-02-05 19:08:08 -06:00
await equipHighestAttack ( bot )
2024-01-23 18:01:38 -06:00
if ( ! kill ) {
if ( bot . entity . position . distanceTo ( pos ) > 5 ) {
console . log ( 'moving to mob...' )
await goToPosition ( bot , pos . x , pos . y , pos . z ) ;
2023-11-19 17:11:46 -06:00
}
2024-01-23 18:01:38 -06:00
console . log ( 'attacking mob...' )
await bot . attack ( entity ) ;
}
else {
bot . pvp . attack ( entity ) ;
2024-04-20 22:22:26 -05:00
while ( world . getNearbyEntities ( bot , 24 ) . includes ( entity ) ) {
2024-01-23 18:01:38 -06:00
await new Promise ( resolve => setTimeout ( resolve , 1000 ) ) ;
if ( bot . interrupt _code ) {
bot . pvp . stop ( ) ;
return false ;
2023-11-19 17:11:46 -06:00
}
2023-09-29 15:53:16 -07:00
}
2024-01-23 18:01:38 -06:00
log ( bot , ` Successfully killed ${ entity . name } . ` ) ;
2024-02-02 15:47:17 -06:00
await pickupNearbyItems ( bot ) ;
2024-01-23 18:01:38 -06:00
return true ;
}
}
2023-11-19 17:11:46 -06:00
2024-02-01 16:16:30 -06:00
export async function defendSelf ( bot , range = 9 ) {
2024-01-23 18:01:38 -06:00
/ * *
* Defend yourself from all nearby hostile mobs until there are no more .
* @ param { MinecraftBot } bot , reference to the minecraft bot .
* @ param { number } range , the range to look for mobs . Defaults to 8.
* @ returns { Promise < boolean > } true if the bot found any enemies and has killed them , false if no entities were found .
* @ example
* await skills . defendSelf ( bot ) ;
* * * /
bot . modes . pause ( 'self_defense' ) ;
2024-04-13 22:56:18 -05:00
bot . modes . pause ( 'cowardice' ) ;
2024-01-23 18:01:38 -06:00
let attacked = false ;
2024-01-25 13:25:36 -08:00
let enemy = world . getNearestEntityWhere ( bot , entity => mc . isHostile ( entity ) , range ) ;
2024-01-23 18:01:38 -06:00
while ( enemy ) {
2024-02-05 19:08:08 -06:00
await equipHighestAttack ( bot ) ;
2024-10-10 22:17:39 -05:00
if ( bot . entity . position . distanceTo ( enemy . position ) >= 4 && enemy . name !== 'creeper' && enemy . name !== 'phantom' ) {
2024-01-23 18:01:38 -06:00
try {
bot . pathfinder . setMovements ( new pf . Movements ( bot ) ) ;
2024-10-10 22:17:39 -05:00
await bot . pathfinder . goto ( new pf . goals . GoalFollow ( enemy , 3.5 ) , true ) ;
} catch ( err ) { /* might error if entity dies, ignore */ }
}
if ( bot . entity . position . distanceTo ( enemy . position ) <= 2 ) {
try {
bot . pathfinder . setMovements ( new pf . Movements ( bot ) ) ;
let inverted _goal = new pf . goals . GoalInvert ( new pf . goals . GoalFollow ( enemy , 2 ) ) ;
await bot . pathfinder . goto ( inverted _goal , true ) ;
2024-01-23 18:01:38 -06:00
} catch ( err ) { /* might error if entity dies, ignore */ }
}
bot . pvp . attack ( enemy ) ;
attacked = true ;
await new Promise ( resolve => setTimeout ( resolve , 500 ) ) ;
2024-01-25 13:25:36 -08:00
enemy = world . getNearestEntityWhere ( bot , entity => mc . isHostile ( entity ) , range ) ;
2024-01-23 18:01:38 -06:00
if ( bot . interrupt _code ) {
bot . pvp . stop ( ) ;
return false ;
}
2023-09-29 15:53:16 -07:00
}
2024-01-24 17:24:52 -06:00
bot . pvp . stop ( ) ;
2024-01-23 18:01:38 -06:00
if ( attacked )
log ( bot , ` Successfully defended self. ` ) ;
else
log ( bot , ` No enemies nearby to defend self from. ` ) ;
return attacked ;
2023-09-29 15:53:16 -07:00
}
2024-01-23 18:01:38 -06:00
2024-03-06 13:18:23 -08:00
export async function collectBlock ( bot , blockType , num = 1 , exclude = null ) {
2023-11-07 09:44:56 -06:00
/ * *
* Collect one of the given block type .
* @ param { MinecraftBot } bot , reference to the minecraft bot .
* @ param { string } blockType , the type of block to collect .
2023-12-04 21:33:40 -06:00
* @ param { number } num , the number of blocks to collect . Defaults to 1.
2023-11-07 09:44:56 -06:00
* @ returns { Promise < boolean > } true if the block was collected , false if the block type was not found .
* @ example
* await skills . collectBlock ( bot , "oak_log" ) ;
* * /
2023-12-06 22:15:09 -06:00
if ( num < 1 ) {
log ( bot , ` Invalid number of blocks to collect: ${ num } . ` ) ;
return false ;
}
2024-01-27 19:17:36 -06:00
let blocktypes = [ blockType ] ;
2024-04-30 23:07:07 -05:00
if ( blockType === 'coal' || blockType === 'diamond' || blockType === 'emerald' || blockType === 'iron' || blockType === 'gold' || blockType === 'lapis_lazuli' || blockType === 'redstone' )
blocktypes . push ( blockType + '_ore' ) ;
2024-01-27 19:17:36 -06:00
if ( blockType . endsWith ( 'ore' ) )
blocktypes . push ( 'deepslate_' + blockType ) ;
2024-03-06 14:32:54 -08:00
if ( blockType === 'dirt' )
blocktypes . push ( 'grass_block' ) ;
2024-01-27 19:17:36 -06:00
2023-12-04 21:33:40 -06:00
let collected = 0 ;
2024-02-01 16:16:30 -06:00
for ( let i = 0 ; i < num ; i ++ ) {
2024-03-06 14:32:54 -08:00
let blocks = world . getNearestBlocks ( bot , blocktypes , 64 ) ;
2024-03-06 13:18:23 -08:00
if ( exclude ) {
for ( let position of exclude ) {
blocks = blocks . filter (
block => block . position . x !== position . x || block . position . y !== position . y || block . position . z !== position . z
) ;
}
}
2024-09-27 17:03:00 -05:00
const movements = new pf . Movements ( bot ) ;
movements . dontMineUnderFallingBlock = false ;
blocks = blocks . filter (
block => movements . safeToBreak ( block )
) ;
2024-02-01 16:16:30 -06:00
if ( blocks . length === 0 ) {
if ( collected === 0 )
log ( bot , ` No ${ blockType } nearby to collect. ` ) ;
else
log ( bot , ` No more ${ blockType } nearby to collect. ` ) ;
break ;
}
const block = blocks [ 0 ] ;
await bot . tool . equipForBlock ( block ) ;
const itemId = bot . heldItem ? bot . heldItem . type : null
if ( ! block . canHarvest ( itemId ) ) {
log ( bot , ` Don't have right tools to harvest ${ blockType } . ` ) ;
return false ;
}
2023-12-04 21:33:40 -06:00
try {
await bot . collectBlock . collect ( block ) ;
collected ++ ;
2024-02-01 16:16:30 -06:00
await autoLight ( bot ) ;
2023-11-27 21:07:52 -06:00
}
2023-12-04 21:33:40 -06:00
catch ( err ) {
if ( err . name === 'NoChests' ) {
log ( bot , ` Failed to collect ${ blockType } : Inventory full, no place to deposit. ` ) ;
break ;
}
else {
log ( bot , ` Failed to collect ${ blockType } : ${ err } . ` ) ;
continue ;
}
2023-12-08 16:18:20 -06:00
}
2024-01-23 18:01:38 -06:00
2023-12-08 16:18:20 -06:00
if ( bot . interrupt _code )
break ;
2023-09-29 15:53:16 -07:00
}
2023-12-04 21:33:40 -06:00
log ( bot , ` Collected ${ collected } ${ blockType } . ` ) ;
2024-02-05 13:21:32 -06:00
return collected > 0 ;
2023-12-04 21:33:40 -06:00
}
2024-02-02 15:34:17 -06:00
export async function pickupNearbyItems ( bot ) {
2023-12-04 21:33:40 -06:00
/ * *
* Pick up all nearby items .
* @ param { MinecraftBot } bot , reference to the minecraft bot .
* @ returns { Promise < boolean > } true if the items were picked up , false otherwise .
* @ example
2024-02-02 15:47:17 -06:00
* await skills . pickupNearbyItems ( bot ) ;
2023-12-04 21:33:40 -06:00
* * /
2024-02-02 15:34:17 -06:00
const distance = 8 ;
const getNearestItem = bot => bot . nearestEntity ( entity => entity . name === 'item' && bot . entity . position . distanceTo ( entity . position ) < distance ) ;
let nearestItem = getNearestItem ( bot ) ;
let pickedUp = 0 ;
while ( nearestItem ) {
bot . pathfinder . setMovements ( new pf . Movements ( bot ) ) ;
await bot . pathfinder . goto ( new pf . goals . GoalFollow ( nearestItem , 0.8 ) , true ) ;
await new Promise ( resolve => setTimeout ( resolve , 200 ) ) ;
let prev = nearestItem ;
nearestItem = getNearestItem ( bot ) ;
if ( prev === nearestItem ) {
break ;
}
pickedUp ++ ;
2023-12-04 21:33:40 -06:00
}
2024-02-02 15:34:17 -06:00
log ( bot , ` Picked up ${ pickedUp } items. ` ) ;
2023-12-04 21:33:40 -06:00
return true ;
2023-09-29 15:53:16 -07:00
}
export async function breakBlockAt ( bot , x , y , z ) {
2023-11-07 09:44:56 -06:00
/ * *
* Break the block at the given position . Will use the bot ' s equipped item .
* @ param { MinecraftBot } bot , reference to the minecraft bot .
* @ param { number } x , the x coordinate of the block to break .
* @ param { number } y , the y coordinate of the block to break .
* @ param { number } z , the z coordinate of the block to break .
* @ returns { Promise < boolean > } true if the block was broken , false otherwise .
* @ example
2023-11-07 20:21:19 -08:00
* let position = world . getPosition ( bot ) ;
2023-11-07 09:44:56 -06:00
* await skills . breakBlockAt ( bot , position . x , position . y - 1 , position . x ) ;
* * /
2024-02-16 11:57:48 -06:00
if ( x == null || y == null || z == null ) throw new Error ( 'Invalid position to break block at.' ) ;
2024-02-03 12:00:33 -06:00
let block = bot . blockAt ( Vec3 ( x , y , z ) ) ;
if ( block . name !== 'air' && block . name !== 'water' && block . name !== 'lava' ) {
2024-06-03 18:23:01 -05:00
if ( bot . modes . isOn ( 'cheat' ) ) {
let msg = '/setblock ' + Math . floor ( x ) + ' ' + Math . floor ( y ) + ' ' + Math . floor ( z ) + ' air' ;
bot . chat ( msg ) ;
log ( bot , ` Used /setblock to break block at ${ x } , ${ y } , ${ z } . ` ) ;
return true ;
}
2024-02-03 12:00:33 -06:00
if ( bot . entity . position . distanceTo ( block . position ) > 4.5 ) {
let pos = block . position ;
let movements = new pf . Movements ( bot ) ;
movements . canPlaceOn = false ;
movements . allow1by1towers = false ;
2024-02-05 19:08:08 -06:00
bot . pathfinder . setMovements ( movements ) ;
2024-02-03 12:00:33 -06:00
await bot . pathfinder . goto ( new pf . goals . GoalNear ( pos . x , pos . y , pos . z , 4 ) ) ;
}
2024-05-18 12:06:50 -05:00
if ( bot . game . gameMode !== 'creative' ) {
2024-05-14 21:24:41 -05:00
await bot . tool . equipForBlock ( block ) ;
const itemId = bot . heldItem ? bot . heldItem . type : null
if ( ! block . canHarvest ( itemId ) ) {
log ( bot , ` Don't have right tools to break ${ block . name } . ` ) ;
return false ;
}
2024-02-16 11:57:48 -06:00
}
2024-02-03 12:00:33 -06:00
await bot . dig ( block , true ) ;
2024-02-16 11:57:48 -06:00
log ( bot , ` Broke ${ block . name } at x: ${ x . toFixed ( 1 ) } , y: ${ y . toFixed ( 1 ) } , z: ${ z . toFixed ( 1 ) } . ` ) ;
}
else {
log ( bot , ` Skipping block at x: ${ x . toFixed ( 1 ) } , y: ${ y . toFixed ( 1 ) } , z: ${ z . toFixed ( 1 ) } because it is ${ block . name } . ` ) ;
return false ;
2024-02-03 12:00:33 -06:00
}
2023-09-29 15:53:16 -07:00
return true ;
}
2024-06-22 15:19:10 -05:00
export async function placeBlock ( bot , blockType , x , y , z , placeOn = 'bottom' , dontCheat = false ) {
2023-11-07 09:44:56 -06:00
/ * *
2023-11-12 23:19:58 -06:00
* Place the given block type at the given position . It will build off from any adjacent blocks . Will fail if there is a block in the way or nothing to build off of .
2023-11-07 09:44:56 -06:00
* @ param { MinecraftBot } bot , reference to the minecraft bot .
* @ param { string } blockType , the type of block to place .
2023-11-08 19:24:24 -06:00
* @ param { number } x , the x coordinate of the block to place .
* @ param { number } y , the y coordinate of the block to place .
* @ param { number } z , the z coordinate of the block to place .
2024-04-21 12:50:36 -05:00
* @ param { string } placeOn , the preferred side of the block to place on . Can be 'top' , 'bottom' , 'north' , 'south' , 'east' , 'west' , or 'side' . Defaults to bottom . Will place on first available side if not possible .
2024-06-22 15:19:10 -05:00
* @ param { boolean } dontCheat , overrides cheat mode to place the block normally . Defaults to false .
2023-11-07 09:44:56 -06:00
* @ returns { Promise < boolean > } true if the block was placed , false otherwise .
* @ example
2024-04-21 12:50:36 -05:00
* let p = world . getPosition ( bot ) ;
* await skills . placeBlock ( bot , "oak_log" , p . x + 2 , p . y , p . x ) ;
* await skills . placeBlock ( bot , "torch" , p . x + 1 , p . y , p . x , 'side' ) ;
2023-11-07 09:44:56 -06:00
* * /
2024-06-03 18:23:01 -05:00
if ( ! mc . getBlockId ( blockType ) ) {
log ( bot , ` Invalid block type: ${ blockType } . ` ) ;
return false ;
}
2024-06-22 15:19:10 -05:00
const target _dest = new Vec3 ( Math . floor ( x ) , Math . floor ( y ) , Math . floor ( z ) ) ;
if ( bot . modes . isOn ( 'cheat' ) && ! dontCheat ) {
2025-01-09 15:15:25 -06:00
if ( bot . restrict _to _inventory ) {
let block = bot . inventory . items ( ) . find ( item => item . name === blockType ) ;
if ( ! block ) {
log ( bot , ` Cannot place ${ blockType } , you are restricted to your current inventory. ` ) ;
return false ;
}
}
2024-06-22 15:19:10 -05:00
// invert the facing direction
let face = placeOn === 'north' ? 'south' : placeOn === 'south' ? 'north' : placeOn === 'east' ? 'west' : 'east' ;
if ( blockType . includes ( 'torch' ) && placeOn !== 'bottom' ) {
// insert wall_ before torch
blockType = blockType . replace ( 'torch' , 'wall_torch' ) ;
if ( placeOn !== 'side' && placeOn !== 'top' ) {
blockType += ` [facing= ${ face } ] ` ;
}
}
if ( blockType . includes ( 'button' ) || blockType === 'lever' ) {
if ( placeOn === 'top' ) {
blockType += ` [face=ceiling] ` ;
}
else if ( placeOn === 'bottom' ) {
blockType += ` [face=floor] ` ;
}
else {
blockType += ` [facing= ${ face } ] ` ;
}
}
2024-06-22 15:35:18 -05:00
if ( blockType === 'ladder' || blockType === 'repeater' || blockType === 'comparator' ) {
2024-06-22 15:19:10 -05:00
blockType += ` [facing= ${ face } ] ` ;
}
2024-12-01 22:28:21 -06:00
if ( blockType . includes ( 'stairs' ) ) {
blockType += ` [facing= ${ face } ] ` ;
}
2024-06-03 18:23:01 -05:00
let msg = '/setblock ' + Math . floor ( x ) + ' ' + Math . floor ( y ) + ' ' + Math . floor ( z ) + ' ' + blockType ;
bot . chat ( msg ) ;
2024-06-22 15:19:10 -05:00
if ( blockType . includes ( 'door' ) )
2024-06-22 16:04:49 -05:00
bot . chat ( '/setblock ' + Math . floor ( x ) + ' ' + Math . floor ( y + 1 ) + ' ' + Math . floor ( z ) + ' ' + blockType + '[half=upper]' ) ;
2024-06-22 15:19:10 -05:00
if ( blockType . includes ( 'bed' ) )
bot . chat ( '/setblock ' + Math . floor ( x ) + ' ' + Math . floor ( y ) + ' ' + Math . floor ( z - 1 ) + ' ' + blockType + '[part=head]' ) ;
log ( bot , ` Used /setblock to place ${ blockType } at ${ target _dest } . ` ) ;
2024-06-03 18:23:01 -05:00
return true ;
}
2024-10-10 17:40:00 -05:00
let item _name = blockType ;
if ( item _name == "redstone_wire" )
item _name = "redstone" ;
let block = bot . inventory . items ( ) . find ( item => item . name === item _name ) ;
2025-01-09 15:15:25 -06:00
if ( ! block && bot . game . gameMode === 'creative' && ! bot . restrict _to _inventory ) {
2024-10-10 17:40:00 -05:00
await bot . creative . setInventorySlot ( 36 , mc . makeItem ( item _name , 1 ) ) ; // 36 is first hotbar slot
block = bot . inventory . items ( ) . find ( item => item . name === item _name ) ;
2024-06-22 15:35:18 -05:00
}
2024-04-02 19:18:13 -05:00
if ( ! block ) {
log ( bot , ` Don't have any ${ blockType } to place. ` ) ;
return false ;
}
2023-12-04 21:33:40 -06:00
const targetBlock = bot . blockAt ( target _dest ) ;
2024-04-02 19:18:13 -05:00
if ( targetBlock . name === blockType ) {
log ( bot , ` ${ blockType } already at ${ targetBlock . position } . ` ) ;
2023-11-12 23:19:58 -06:00
return false ;
}
2024-04-05 16:58:08 -05:00
const empty _blocks = [ 'air' , 'water' , 'lava' , 'grass' , 'short_grass' , 'tall_grass' , 'snow' , 'dead_bush' , 'fern' ] ;
2024-04-02 19:18:13 -05:00
if ( ! empty _blocks . includes ( targetBlock . name ) ) {
log ( bot , ` ${ blockType } in the way at ${ targetBlock . position } . ` ) ;
const removed = await breakBlockAt ( bot , x , y , z ) ;
if ( ! removed ) {
log ( bot , ` Cannot place ${ blockType } at ${ targetBlock . position } : block in the way. ` ) ;
return false ;
}
await new Promise ( resolve => setTimeout ( resolve , 200 ) ) ; // wait for block to break
}
2023-11-12 23:19:58 -06:00
// get the buildoffblock and facevec based on whichever adjacent block is not empty
let buildOffBlock = null ;
let faceVec = null ;
2024-04-21 12:50:36 -05:00
const dir _map = {
'top' : Vec3 ( 0 , 1 , 0 ) ,
'bottom' : Vec3 ( 0 , - 1 , 0 ) ,
'north' : Vec3 ( 0 , 0 , - 1 ) ,
'south' : Vec3 ( 0 , 0 , 1 ) ,
'east' : Vec3 ( 1 , 0 , 0 ) ,
'west' : Vec3 ( - 1 , 0 , 0 ) ,
}
let dirs = [ ] ;
if ( placeOn === 'side' ) {
dirs . push ( dir _map [ 'north' ] , dir _map [ 'south' ] , dir _map [ 'east' ] , dir _map [ 'west' ] ) ;
}
else if ( dir _map [ placeOn ] !== undefined ) {
dirs . push ( dir _map [ placeOn ] ) ;
}
else {
dirs . push ( dir _map [ 'bottom' ] ) ;
log ( bot , ` Unknown placeOn value " ${ placeOn } ". Defaulting to bottom. ` ) ;
}
dirs . push ( ... Object . values ( dir _map ) . filter ( d => ! dirs . includes ( d ) ) ) ;
2023-11-12 23:19:58 -06:00
for ( let d of dirs ) {
2023-12-04 21:33:40 -06:00
const block = bot . blockAt ( target _dest . plus ( d ) ) ;
2023-11-12 23:19:58 -06:00
if ( ! empty _blocks . includes ( block . name ) ) {
buildOffBlock = block ;
2024-04-21 12:50:36 -05:00
faceVec = new Vec3 ( - d . x , - d . y , - d . z ) ; // invert
2023-11-12 23:19:58 -06:00
break ;
}
}
if ( ! buildOffBlock ) {
2023-12-04 21:33:40 -06:00
log ( bot , ` Cannot place ${ blockType } at ${ targetBlock . position } : nothing to place on. ` ) ;
2023-11-12 23:19:58 -06:00
return false ;
}
2024-01-23 18:01:38 -06:00
const pos = bot . entity . position ;
const pos _above = pos . plus ( Vec3 ( 0 , 1 , 0 ) ) ;
2024-10-10 17:40:00 -05:00
const dont _move _for = [ 'torch' , 'redstone_torch' , 'redstone_wire' , 'lever' , 'button' , 'rail' , 'detector_rail' , 'powered_rail' , 'activator_rail' , 'tripwire_hook' , 'tripwire' , 'water_bucket' ] ;
2024-01-23 18:01:38 -06:00
if ( ! dont _move _for . includes ( blockType ) && ( pos . distanceTo ( targetBlock . position ) < 1 || pos _above . distanceTo ( targetBlock . position ) < 1 ) ) {
// too close
let goal = new pf . goals . GoalNear ( targetBlock . position . x , targetBlock . position . y , targetBlock . position . z , 2 ) ;
let inverted _goal = new pf . goals . GoalInvert ( goal ) ;
bot . pathfinder . setMovements ( new pf . Movements ( bot ) ) ;
await bot . pathfinder . goto ( inverted _goal ) ;
2023-11-19 17:11:46 -06:00
}
if ( bot . entity . position . distanceTo ( targetBlock . position ) > 4.5 ) {
2024-01-23 18:01:38 -06:00
// too far
2023-11-19 17:11:46 -06:00
let pos = targetBlock . position ;
2024-03-23 11:15:53 -05:00
let movements = new pf . Movements ( bot ) ;
bot . pathfinder . setMovements ( movements ) ;
2023-11-19 17:11:46 -06:00
await bot . pathfinder . goto ( new pf . goals . GoalNear ( pos . x , pos . y , pos . z , 4 ) ) ;
}
2023-12-04 21:33:40 -06:00
await bot . equip ( block , 'hand' ) ;
await bot . lookAt ( buildOffBlock . position ) ;
2023-11-13 00:57:20 -06:00
2023-12-04 21:33:40 -06:00
// will throw error if an entity is in the way, and sometimes even if the block was placed
try {
await bot . placeBlock ( buildOffBlock , faceVec ) ;
2024-08-22 15:57:20 -05:00
log ( bot , ` Placed ${ blockType } at ${ target _dest } . ` ) ;
2023-12-04 21:33:40 -06:00
await new Promise ( resolve => setTimeout ( resolve , 200 ) ) ;
return true ;
} catch ( err ) {
log ( bot , ` Failed to place ${ blockType } at ${ target _dest } . ` ) ;
2023-11-12 23:19:58 -06:00
return false ;
}
2023-09-29 15:53:16 -07:00
}
2024-09-26 22:28:46 -05:00
export async function equip ( bot , itemName ) {
2023-11-07 09:44:56 -06:00
/ * *
2024-09-26 22:28:46 -05:00
* Equip the given item to the proper body part , like tools or armor .
2023-11-07 09:44:56 -06:00
* @ param { MinecraftBot } bot , reference to the minecraft bot .
* @ param { string } itemName , the item or block name to equip .
* @ returns { Promise < boolean > } true if the item was equipped , false otherwise .
* @ example
2024-09-26 22:28:46 -05:00
* await skills . equip ( bot , "iron_pickaxe" ) ;
2023-12-04 21:33:40 -06:00
* * /
2024-10-15 17:04:19 -05:00
let item = bot . inventory . slots . find ( slot => slot && slot . name === itemName ) ;
2023-12-04 21:33:40 -06:00
if ( ! item ) {
log ( bot , ` You do not have any ${ itemName } to equip. ` ) ;
return false ;
}
2024-09-26 22:28:46 -05:00
if ( itemName . includes ( 'leggings' ) ) {
await bot . equip ( item , 'legs' ) ;
}
else if ( itemName . includes ( 'boots' ) ) {
await bot . equip ( item , 'feet' ) ;
}
else if ( itemName . includes ( 'helmet' ) ) {
await bot . equip ( item , 'head' ) ;
}
2024-10-15 17:04:19 -05:00
else if ( itemName . includes ( 'chestplate' ) || itemName . includes ( 'elytra' ) ) {
2024-09-26 22:28:46 -05:00
await bot . equip ( item , 'torso' ) ;
}
2024-10-25 23:46:29 -05:00
else if ( itemName . includes ( 'shield' ) ) {
await bot . equip ( item , 'off-hand' ) ;
}
2024-09-26 22:28:46 -05:00
else {
await bot . equip ( item , 'hand' ) ;
}
2024-10-15 17:04:19 -05:00
log ( bot , ` Equipped ${ itemName } . ` ) ;
2023-12-04 21:33:40 -06:00
return true ;
}
export async function discard ( bot , itemName , num = - 1 ) {
/ * *
* Discard the given item .
* @ param { MinecraftBot } bot , reference to the minecraft bot .
* @ param { string } itemName , the item or block name to discard .
* @ param { number } num , the number of items to discard . Defaults to - 1 , which discards all items .
* @ returns { Promise < boolean > } true if the item was discarded , false otherwise .
* @ example
* await skills . discard ( bot , "oak_log" ) ;
2023-11-07 09:44:56 -06:00
* * /
2023-12-04 21:33:40 -06:00
let discarded = 0 ;
while ( true ) {
let item = bot . inventory . items ( ) . find ( item => item . name === itemName ) ;
if ( ! item ) {
break ;
}
let to _discard = num === - 1 ? item . count : Math . min ( num - discarded , item . count ) ;
await bot . toss ( item . type , null , to _discard ) ;
discarded += to _discard ;
if ( num !== - 1 && discarded >= num ) {
2023-09-29 15:53:16 -07:00
break ;
}
}
2023-12-04 21:33:40 -06:00
if ( discarded === 0 ) {
log ( bot , ` You do not have any ${ itemName } to discard. ` ) ;
2023-09-29 15:53:16 -07:00
return false ;
2023-12-04 21:33:40 -06:00
}
2024-12-05 15:30:25 -06:00
log ( bot , ` Discarded ${ discarded } ${ itemName } . ` ) ;
2023-09-29 15:53:16 -07:00
return true ;
}
2024-09-27 17:03:00 -05:00
export async function putInChest ( bot , itemName , num = - 1 ) {
/ * *
* Put the given item in the nearest chest .
* @ param { MinecraftBot } bot , reference to the minecraft bot .
* @ param { string } itemName , the item or block name to put in the chest .
* @ param { number } num , the number of items to put in the chest . Defaults to - 1 , which puts all items .
* @ returns { Promise < boolean > } true if the item was put in the chest , false otherwise .
* @ example
* await skills . putInChest ( bot , "oak_log" ) ;
* * /
let chest = world . getNearestBlock ( bot , 'chest' , 32 ) ;
if ( ! chest ) {
log ( bot , ` Could not find a chest nearby. ` ) ;
return false ;
}
let item = bot . inventory . items ( ) . find ( item => item . name === itemName ) ;
if ( ! item ) {
log ( bot , ` You do not have any ${ itemName } to put in the chest. ` ) ;
return false ;
}
let to _put = num === - 1 ? item . count : Math . min ( num , item . count ) ;
await goToPosition ( bot , chest . position . x , chest . position . y , chest . position . z , 2 ) ;
const chestContainer = await bot . openContainer ( chest ) ;
await chestContainer . deposit ( item . type , null , to _put ) ;
await chestContainer . close ( ) ;
log ( bot , ` Successfully put ${ to _put } ${ itemName } in the chest. ` ) ;
return true ;
}
export async function takeFromChest ( bot , itemName , num = - 1 ) {
/ * *
* Take the given item from the nearest chest .
* @ param { MinecraftBot } bot , reference to the minecraft bot .
* @ param { string } itemName , the item or block name to take from the chest .
* @ param { number } num , the number of items to take from the chest . Defaults to - 1 , which takes all items .
* @ returns { Promise < boolean > } true if the item was taken from the chest , false otherwise .
* @ example
* await skills . takeFromChest ( bot , "oak_log" ) ;
* * * /
let chest = world . getNearestBlock ( bot , 'chest' , 32 ) ;
if ( ! chest ) {
log ( bot , ` Could not find a chest nearby. ` ) ;
return false ;
}
await goToPosition ( bot , chest . position . x , chest . position . y , chest . position . z , 2 ) ;
const chestContainer = await bot . openContainer ( chest ) ;
let item = chestContainer . containerItems ( ) . find ( item => item . name === itemName ) ;
if ( ! item ) {
log ( bot , ` Could not find any ${ itemName } in the chest. ` ) ;
await chestContainer . close ( ) ;
return false ;
}
let to _take = num === - 1 ? item . count : Math . min ( num , item . count ) ;
await chestContainer . withdraw ( item . type , null , to _take ) ;
await chestContainer . close ( ) ;
log ( bot , ` Successfully took ${ to _take } ${ itemName } from the chest. ` ) ;
return true ;
}
export async function viewChest ( bot ) {
/ * *
* View the contents of the nearest chest .
* @ param { MinecraftBot } bot , reference to the minecraft bot .
* @ returns { Promise < boolean > } true if the chest was viewed , false otherwise .
* @ example
* await skills . viewChest ( bot ) ;
* * * /
let chest = world . getNearestBlock ( bot , 'chest' , 32 ) ;
if ( ! chest ) {
log ( bot , ` Could not find a chest nearby. ` ) ;
return false ;
}
await goToPosition ( bot , chest . position . x , chest . position . y , chest . position . z , 2 ) ;
const chestContainer = await bot . openContainer ( chest ) ;
let items = chestContainer . containerItems ( ) ;
if ( items . length === 0 ) {
log ( bot , ` The chest is empty. ` ) ;
}
else {
log ( bot , ` The chest contains: ` ) ;
for ( let item of items ) {
log ( bot , ` ${ item . count } ${ item . name } ` ) ;
}
}
await chestContainer . close ( ) ;
return true ;
}
2024-12-05 15:30:25 -06:00
export async function consume ( bot , itemName = "" ) {
2023-11-07 09:44:56 -06:00
/ * *
2024-12-05 15:30:25 -06:00
* Eat / drink the given item .
2023-11-07 09:44:56 -06:00
* @ param { MinecraftBot } bot , reference to the minecraft bot .
2024-12-05 15:30:25 -06:00
* @ param { string } itemName , the item to eat / drink .
2023-12-04 21:33:40 -06:00
* @ returns { Promise < boolean > } true if the item was eaten , false otherwise .
2023-11-07 09:44:56 -06:00
* @ example
2023-12-04 21:33:40 -06:00
* await skills . eat ( bot , "apple" ) ;
2023-11-07 09:44:56 -06:00
* * /
2023-12-04 21:33:40 -06:00
let item , name ;
2024-12-05 15:30:25 -06:00
if ( itemName ) {
item = bot . inventory . items ( ) . find ( item => item . name === itemName ) ;
name = itemName ;
2023-12-04 21:33:40 -06:00
}
if ( ! item ) {
log ( bot , ` You do not have any ${ name } to eat. ` ) ;
return false ;
}
await bot . equip ( item , 'hand' ) ;
await bot . consume ( ) ;
2024-12-05 15:30:25 -06:00
log ( bot , ` Consumed ${ item . name } . ` ) ;
2023-09-29 15:53:16 -07:00
return true ;
}
2023-12-04 21:33:40 -06:00
export async function giveToPlayer ( bot , itemType , username , num = 1 ) {
2023-11-07 09:44:56 -06:00
/ * *
* Give one of the specified item to the specified player
* @ param { MinecraftBot } bot , reference to the minecraft bot .
* @ param { string } itemType , the name of the item to give .
* @ param { string } username , the username of the player to give the item to .
2023-12-04 21:33:40 -06:00
* @ param { number } num , the number of items to give . Defaults to 1.
2023-11-07 09:44:56 -06:00
* @ returns { Promise < boolean > } true if the item was given , false otherwise .
* @ example
* await skills . giveToPlayer ( bot , "oak_log" , "player1" ) ;
* * /
2023-09-29 15:53:16 -07:00
let player = bot . players [ username ] . entity
2024-11-05 12:17:10 -06:00
if ( ! player ) {
2023-11-27 21:33:44 -06:00
log ( bot , ` Could not find ${ username } . ` ) ;
2023-09-29 15:53:16 -07:00
return false ;
2023-11-27 21:33:44 -06:00
}
2024-12-05 15:30:25 -06:00
await goToPlayer ( bot , username , 3 ) ;
// if we are 2 below the player
log ( bot , bot . entity . position . y , player . position . y ) ;
if ( bot . entity . position . y < player . position . y - 1 ) {
await goToPlayer ( bot , username , 1 ) ;
}
// if we are too close, make some distance
if ( bot . entity . position . distanceTo ( player . position ) < 2 ) {
2024-12-12 19:42:29 -06:00
await moveAwayFromEntity ( bot , player , 2 ) ;
2024-12-05 15:30:25 -06:00
}
2023-12-04 21:33:40 -06:00
await bot . lookAt ( player . position ) ;
2024-11-05 12:17:10 -06:00
if ( await discard ( bot , itemType , num ) ) {
2024-12-05 15:30:25 -06:00
let given = false ;
bot . once ( 'playerCollect' , ( collector , collected ) => {
console . log ( collected . name ) ;
if ( collector . username === username ) {
2025-01-06 14:59:51 +08:00
log ( bot , ` ${ username } received ${ itemType } . ` ) ;
2024-12-05 15:30:25 -06:00
given = true ;
}
} ) ;
let start = Date . now ( ) ;
while ( ! given && ! bot . interrupt _code ) {
await new Promise ( resolve => setTimeout ( resolve , 500 ) ) ;
if ( given ) {
return true ;
}
if ( Date . now ( ) - start > 3000 ) {
break ;
}
}
2024-11-05 12:17:10 -06:00
}
2024-12-05 15:30:25 -06:00
log ( bot , ` Failed to give ${ itemType } to ${ username } , it was never received. ` ) ;
2024-11-05 12:17:10 -06:00
return false ;
2023-12-04 21:33:40 -06:00
}
2024-01-23 18:01:38 -06:00
2023-12-04 21:33:40 -06:00
export async function goToPosition ( bot , x , y , z , min _distance = 2 ) {
/ * *
* Navigate to the given position .
* @ param { MinecraftBot } bot , reference to the minecraft bot .
* @ param { number } x , the x coordinate to navigate to . If null , the bot ' s current x coordinate will be used .
* @ param { number } y , the y coordinate to navigate to . If null , the bot ' s current y coordinate will be used .
* @ param { number } z , the z coordinate to navigate to . If null , the bot ' s current z coordinate will be used .
* @ param { number } distance , the distance to keep from the position . Defaults to 2.
* @ returns { Promise < boolean > } true if the position was reached , false otherwise .
* @ example
2024-01-25 13:25:36 -08:00
* let position = world . world . getNearestBlock ( bot , "oak_log" , 64 ) . position ;
2023-12-04 21:33:40 -06:00
* await skills . goToPosition ( bot , position . x , position . y , position . x + 20 ) ;
* * /
if ( x == null || y == null || z == null ) {
log ( bot , ` Missing coordinates, given x: ${ x } y: ${ y } z: ${ z } ` ) ;
2023-09-29 15:53:16 -07:00
return false ;
2023-11-27 21:33:44 -06:00
}
2024-06-03 18:33:00 -05:00
if ( bot . modes . isOn ( 'cheat' ) ) {
bot . chat ( '/tp @s ' + x + ' ' + y + ' ' + z ) ;
log ( bot , ` Teleported to ${ x } , ${ y } , ${ z } . ` ) ;
return true ;
}
2023-12-04 21:33:40 -06:00
bot . pathfinder . setMovements ( new pf . Movements ( bot ) ) ;
await bot . pathfinder . goto ( new pf . goals . GoalNear ( x , y , z , min _distance ) ) ;
log ( bot , ` You have reached at ${ x } , ${ y } , ${ z } . ` ) ;
2023-09-29 15:53:16 -07:00
return true ;
}
2024-08-22 15:57:20 -05:00
export async function goToNearestBlock ( bot , blockType , min _distance = 2 , range = 64 ) {
/ * *
* Navigate to the nearest block of the given type .
* @ param { MinecraftBot } bot , reference to the minecraft bot .
* @ param { string } blockType , the type of block to navigate to .
* @ param { number } min _distance , the distance to keep from the block . Defaults to 2.
* @ param { number } range , the range to look for the block . Defaults to 64.
* @ returns { Promise < boolean > } true if the block was reached , false otherwise .
* @ example
* await skills . goToNearestBlock ( bot , "oak_log" , 64 , 2 ) ;
* * * /
const MAX _RANGE = 512 ;
if ( range > MAX _RANGE ) {
log ( bot , ` Maximum search range capped at ${ MAX _RANGE } . ` ) ;
range = MAX _RANGE ;
}
let block = world . getNearestBlock ( bot , blockType , range ) ;
if ( ! block ) {
log ( bot , ` Could not find any ${ blockType } in ${ range } blocks. ` ) ;
return false ;
}
log ( bot , ` Found ${ blockType } at ${ block . position } . ` ) ;
await goToPosition ( bot , block . position . x , block . position . y , block . position . z , min _distance ) ;
return true ;
}
2023-09-29 15:53:16 -07:00
2024-12-05 15:30:25 -06:00
export async function goToNearestEntity ( bot , entityType , min _distance = 2 , range = 64 ) {
/ * *
* Navigate to the nearest entity of the given type .
* @ param { MinecraftBot } bot , reference to the minecraft bot .
* @ param { string } entityType , the type of entity to navigate to .
* @ param { number } min _distance , the distance to keep from the entity . Defaults to 2.
* @ param { number } range , the range to look for the entity . Defaults to 64.
* @ returns { Promise < boolean > } true if the entity was reached , false otherwise .
* * /
let entity = world . getNearestEntityWhere ( bot , entity => entity . name === entityType , range ) ;
if ( ! entity ) {
log ( bot , ` Could not find any ${ entityType } in ${ range } blocks. ` ) ;
return false ;
}
let distance = bot . entity . position . distanceTo ( entity . position ) ;
log ( bot , ` Found ${ entityType } ${ distance } blocks away. ` ) ;
await goToPosition ( bot , entity . position . x , entity . position . y , entity . position . z , min _distance ) ;
return true ;
}
2024-02-05 19:08:08 -06:00
export async function goToPlayer ( bot , username , distance = 3 ) {
2023-11-07 09:44:56 -06:00
/ * *
* Navigate to the given player .
* @ param { MinecraftBot } bot , reference to the minecraft bot .
* @ param { string } username , the username of the player to navigate to .
2024-02-05 19:08:08 -06:00
* @ param { number } distance , the goal distance to the player .
2023-11-07 09:44:56 -06:00
* @ returns { Promise < boolean > } true if the player was found , false otherwise .
* @ example
* await skills . goToPlayer ( bot , "player" ) ;
* * /
2024-06-03 18:23:01 -05:00
if ( bot . modes . isOn ( 'cheat' ) ) {
bot . chat ( '/tp @s ' + username ) ;
log ( bot , ` Teleported to ${ username } . ` ) ;
return true ;
}
2024-01-23 18:01:38 -06:00
bot . modes . pause ( 'self_defense' ) ;
2024-04-20 22:22:26 -05:00
bot . modes . pause ( 'cowardice' ) ;
2023-08-15 23:39:02 -07:00
let player = bot . players [ username ] . entity
2023-12-04 21:33:40 -06:00
if ( ! player ) {
log ( bot , ` Could not find ${ username } . ` ) ;
2023-08-15 23:39:02 -07:00
return false ;
2023-12-04 21:33:40 -06:00
}
2024-03-23 11:15:53 -05:00
const move = new pf . Movements ( bot ) ;
bot . pathfinder . setMovements ( move ) ;
2024-02-05 19:08:08 -06:00
await bot . pathfinder . goto ( new pf . goals . GoalFollow ( player , distance ) , true ) ;
2024-01-13 12:11:04 -06:00
log ( bot , ` You have reached ${ username } . ` ) ;
2023-08-15 23:39:02 -07:00
}
2023-11-07 09:44:56 -06:00
2024-02-05 19:08:08 -06:00
export async function followPlayer ( bot , username , distance = 4 ) {
2023-11-07 09:44:56 -06:00
/ * *
2023-11-12 17:41:01 -06:00
* Follow the given player endlessly . Will not return until the code is manually stopped .
2023-11-07 09:44:56 -06:00
* @ param { MinecraftBot } bot , reference to the minecraft bot .
* @ param { string } username , the username of the player to follow .
* @ returns { Promise < boolean > } true if the player was found , false otherwise .
* @ example
* await skills . followPlayer ( bot , "player" ) ;
* * /
2024-01-13 12:11:04 -06:00
let player = bot . players [ username ] . entity
if ( ! player )
return false ;
2024-03-23 11:15:53 -05:00
const move = new pf . Movements ( bot ) ;
bot . pathfinder . setMovements ( move ) ;
2024-02-05 19:08:08 -06:00
bot . pathfinder . setGoal ( new pf . goals . GoalFollow ( player , distance ) , true ) ;
2024-01-23 18:01:38 -06:00
log ( bot , ` You are now actively following player ${ username } . ` ) ;
2024-01-13 12:11:04 -06:00
while ( ! bot . interrupt _code ) {
await new Promise ( resolve => setTimeout ( resolve , 500 ) ) ;
2024-08-22 15:57:20 -05:00
// in cheat mode, if the distance is too far, teleport to the player
if ( bot . modes . isOn ( 'cheat' ) && bot . entity . position . distanceTo ( player . position ) > 100 && player . isOnGround ) {
await goToPlayer ( bot , username ) ;
}
2024-09-29 13:35:15 -07:00
if ( bot . modes . isOn ( 'unstuck' ) ) {
2024-10-10 17:40:00 -05:00
const is _nearby = bot . entity . position . distanceTo ( player . position ) <= distance + 1 ;
if ( is _nearby )
bot . modes . pause ( 'unstuck' ) ;
else
bot . modes . unpause ( 'unstuck' ) ;
2024-09-29 13:35:15 -07:00
}
2024-01-13 12:11:04 -06:00
}
2023-11-07 09:44:56 -06:00
return true ;
2024-01-16 15:53:27 -06:00
}
2024-01-23 18:01:38 -06:00
2024-02-02 11:54:17 -06:00
export async function moveAway ( bot , distance ) {
/ * *
* Move away from current position in any direction .
* @ param { MinecraftBot } bot , reference to the minecraft bot .
* @ param { number } distance , the distance to move away .
* @ returns { Promise < boolean > } true if the bot moved away , false otherwise .
* @ example
* await skills . moveAway ( bot , 8 ) ;
* * /
const pos = bot . entity . position ;
let goal = new pf . goals . GoalNear ( pos . x , pos . y , pos . z , distance ) ;
let inverted _goal = new pf . goals . GoalInvert ( goal ) ;
bot . pathfinder . setMovements ( new pf . Movements ( bot ) ) ;
2024-06-03 18:23:01 -05:00
if ( bot . modes . isOn ( 'cheat' ) ) {
2024-08-22 15:57:20 -05:00
const move = new pf . Movements ( bot ) ;
2024-06-03 18:23:01 -05:00
const path = await bot . pathfinder . getPathTo ( move , inverted _goal , 10000 ) ;
let last _move = path . path [ path . path . length - 1 ] ;
console . log ( last _move ) ;
if ( last _move ) {
let x = Math . floor ( last _move . x ) ;
let y = Math . floor ( last _move . y ) ;
let z = Math . floor ( last _move . z ) ;
bot . chat ( '/tp @s ' + x + ' ' + y + ' ' + z ) ;
return true ;
}
}
2024-02-02 11:54:17 -06:00
await bot . pathfinder . goto ( inverted _goal ) ;
let new _pos = bot . entity . position ;
log ( bot , ` Moved away from nearest entity to ${ new _pos } . ` ) ;
return true ;
}
2024-12-12 19:42:29 -06:00
export async function moveAwayFromEntity ( bot , entity , distance = 16 ) {
/ * *
* Move away from the given entity .
* @ param { MinecraftBot } bot , reference to the minecraft bot .
* @ param { Entity } entity , the entity to move away from .
* @ param { number } distance , the distance to move away .
* @ returns { Promise < boolean > } true if the bot moved away , false otherwise .
* * /
let goal = new pf . goals . GoalFollow ( entity , distance ) ;
let inverted _goal = new pf . goals . GoalInvert ( goal ) ;
bot . pathfinder . setMovements ( new pf . Movements ( bot ) ) ;
await bot . pathfinder . goto ( inverted _goal ) ;
return true ;
}
2024-04-13 22:56:18 -05:00
export async function avoidEnemies ( bot , distance = 16 ) {
/ * *
* Move a given distance away from all nearby enemy mobs .
* @ param { MinecraftBot } bot , reference to the minecraft bot .
* @ param { number } distance , the distance to move away .
* @ returns { Promise < boolean > } true if the bot moved away , false otherwise .
* @ example
* await skills . avoidEnemies ( bot , 8 ) ;
* * /
2024-05-04 16:17:41 -05:00
bot . modes . pause ( 'self_preservation' ) ; // prevents damage-on-low-health from interrupting the bot
2024-04-13 22:56:18 -05:00
let enemy = world . getNearestEntityWhere ( bot , entity => mc . isHostile ( entity ) , distance ) ;
while ( enemy ) {
const follow = new pf . goals . GoalFollow ( enemy , distance + 1 ) ; // move a little further away
const inverted _goal = new pf . goals . GoalInvert ( follow ) ;
bot . pathfinder . setMovements ( new pf . Movements ( bot ) ) ;
bot . pathfinder . setGoal ( inverted _goal , true ) ;
await new Promise ( resolve => setTimeout ( resolve , 500 ) ) ;
enemy = world . getNearestEntityWhere ( bot , entity => mc . isHostile ( entity ) , distance ) ;
if ( bot . interrupt _code ) {
2024-05-04 16:17:41 -05:00
break ;
2024-04-13 22:56:18 -05:00
}
2024-10-10 22:17:39 -05:00
if ( enemy && bot . entity . position . distanceTo ( enemy . position ) < 3 ) {
await attackEntity ( bot , enemy , false ) ;
}
2024-04-13 22:56:18 -05:00
}
2024-05-04 16:17:41 -05:00
bot . pathfinder . stop ( ) ;
2024-04-13 22:56:18 -05:00
log ( bot , ` Moved ${ distance } away from enemies. ` ) ;
return true ;
}
2024-10-25 23:46:29 -05:00
export async function stay ( bot , seconds = 30 ) {
2024-02-02 11:54:17 -06:00
/ * *
* Stay in the current position until interrupted . Disables all modes .
* @ param { MinecraftBot } bot , reference to the minecraft bot .
2024-10-25 23:46:29 -05:00
* @ param { number } seconds , the number of seconds to stay . Defaults to 30. - 1 for indefinite .
2024-02-02 11:54:17 -06:00
* @ returns { Promise < boolean > } true if the bot stayed , false otherwise .
* @ example
* await skills . stay ( bot ) ;
* * /
2024-04-20 22:22:26 -05:00
bot . modes . pause ( 'self_preservation' ) ;
2024-10-10 17:40:00 -05:00
bot . modes . pause ( 'unstuck' ) ;
2024-04-13 22:56:18 -05:00
bot . modes . pause ( 'cowardice' ) ;
2024-02-02 11:54:17 -06:00
bot . modes . pause ( 'self_defense' ) ;
bot . modes . pause ( 'hunting' ) ;
bot . modes . pause ( 'torch_placing' ) ;
bot . modes . pause ( 'item_collecting' ) ;
2024-10-25 23:46:29 -05:00
let start = Date . now ( ) ;
while ( ! bot . interrupt _code && ( seconds === - 1 || Date . now ( ) - start < seconds * 1000 ) ) {
2024-02-02 11:54:17 -06:00
await new Promise ( resolve => setTimeout ( resolve , 500 ) ) ;
2024-01-13 12:11:04 -06:00
}
2024-10-25 23:46:29 -05:00
log ( bot , ` Stayed for ${ ( Date . now ( ) - start ) / 1000 } seconds. ` ) ;
2023-11-07 09:44:56 -06:00
return true ;
2024-01-16 15:53:27 -06:00
}
2024-03-20 16:03:16 -07:00
export async function useDoor ( bot , door _pos = null ) {
/ * *
* Use the door at the given position .
* @ param { MinecraftBot } bot , reference to the minecraft bot .
* @ param { Vec3 } door _pos , the position of the door to use . If null , the nearest door will be used .
* @ returns { Promise < boolean > } true if the door was used , false otherwise .
* @ example
* let door = world . getNearestBlock ( bot , "oak_door" , 16 ) . position ;
* await skills . useDoor ( bot , door ) ;
* * /
if ( ! door _pos ) {
for ( let door _type of [ 'oak_door' , 'spruce_door' , 'birch_door' , 'jungle_door' , 'acacia_door' , 'dark_oak_door' ,
'mangrove_door' , 'cherry_door' , 'bamboo_door' , 'crimson_door' , 'warped_door' ] ) {
door _pos = world . getNearestBlock ( bot , door _type , 16 ) . position ;
if ( door _pos ) break ;
}
} else {
door _pos = Vec3 ( door _pos . x , door _pos . y , door _pos . z ) ;
}
if ( ! door _pos ) {
log ( bot , ` Could not find a door to use. ` ) ;
return false ;
}
bot . pathfinder . setGoal ( new pf . goals . GoalNear ( door _pos . x , door _pos . y , door _pos . z , 1 ) ) ;
await new Promise ( ( resolve ) => setTimeout ( resolve , 1000 ) ) ;
while ( bot . pathfinder . isMoving ( ) ) {
await new Promise ( ( resolve ) => setTimeout ( resolve , 100 ) ) ;
}
let door _block = bot . blockAt ( door _pos ) ;
await bot . lookAt ( door _pos ) ;
if ( ! door _block . _properties . open )
await bot . activateBlock ( door _block ) ;
bot . setControlState ( "forward" , true ) ;
await new Promise ( ( resolve ) => setTimeout ( resolve , 600 ) ) ;
bot . setControlState ( "forward" , false ) ;
await bot . activateBlock ( door _block ) ;
log ( bot , ` Used door at ${ door _pos } . ` ) ;
return true ;
}
2024-01-23 18:01:38 -06:00
2024-01-16 15:53:27 -06:00
export async function goToBed ( bot ) {
/ * *
* Sleep in the nearest bed .
* @ param { MinecraftBot } bot , reference to the minecraft bot .
* @ returns { Promise < boolean > } true if the bed was found , false otherwise .
* @ example
* await skills . goToBed ( bot ) ;
* * /
const beds = bot . findBlocks ( {
matching : ( block ) => {
return block . name . includes ( 'bed' ) ;
} ,
maxDistance : 32 ,
count : 1
} ) ;
if ( beds . length === 0 ) {
log ( bot , ` Could not find a bed to sleep in. ` ) ;
return false ;
}
let loc = beds [ 0 ] ;
await goToPosition ( bot , loc . x , loc . y , loc . z ) ;
const bed = bot . blockAt ( loc ) ;
await bot . sleep ( bed ) ;
log ( bot , ` You are in bed. ` ) ;
2024-10-12 20:40:16 -05:00
bot . modes . pause ( 'unstuck' ) ;
2024-01-16 15:53:27 -06:00
while ( bot . isSleeping ) {
await new Promise ( resolve => setTimeout ( resolve , 500 ) ) ;
}
log ( bot , ` You have woken up. ` ) ;
return true ;
}
2024-03-23 11:15:53 -05:00
export async function tillAndSow ( bot , x , y , z , seedType = null ) {
/ * *
* Till the ground at the given position and plant the given seed type .
* @ param { MinecraftBot } bot , reference to the minecraft bot .
* @ param { number } x , the x coordinate to till .
* @ param { number } y , the y coordinate to till .
* @ param { number } z , the z coordinate to till .
* @ param { string } plantType , the type of plant to plant . Defaults to none , which will only till the ground .
* @ returns { Promise < boolean > } true if the ground was tilled , false otherwise .
* @ example
* let position = world . getPosition ( bot ) ;
* await skills . till ( bot , position . x , position . y - 1 , position . x ) ;
* * /
console . log ( x , y , z )
x = Math . round ( x ) ;
y = Math . round ( y ) ;
z = Math . round ( z ) ;
let block = bot . blockAt ( new Vec3 ( x , y , z ) ) ;
console . log ( x , y , z )
if ( block . name !== 'grass_block' && block . name !== 'dirt' && block . name !== 'farmland' ) {
log ( bot , ` Cannot till ${ block . name } , must be grass_block or dirt. ` ) ;
return false ;
}
let above = bot . blockAt ( new Vec3 ( x , y + 1 , z ) ) ;
if ( above . name !== 'air' ) {
log ( bot , ` Cannot till, there is ${ above . name } above the block. ` ) ;
return false ;
}
// if distance is too far, move to the block
if ( bot . entity . position . distanceTo ( block . position ) > 4.5 ) {
let pos = block . position ;
bot . pathfinder . setMovements ( new pf . Movements ( bot ) ) ;
await bot . pathfinder . goto ( new pf . goals . GoalNear ( pos . x , pos . y , pos . z , 4 ) ) ;
}
if ( block . name !== 'farmland' ) {
let hoe = bot . inventory . items ( ) . find ( item => item . name . includes ( 'hoe' ) ) ;
if ( ! hoe ) {
log ( bot , ` Cannot till, no hoes. ` ) ;
return false ;
}
await bot . equip ( hoe , 'hand' ) ;
await bot . activateBlock ( block ) ;
log ( bot , ` Tilled block x: ${ x . toFixed ( 1 ) } , y: ${ y . toFixed ( 1 ) } , z: ${ z . toFixed ( 1 ) } . ` ) ;
}
if ( seedType ) {
if ( seedType . endsWith ( 'seed' ) && ! seedType . endsWith ( 'seeds' ) )
seedType += 's' ; // fixes common mistake
let seeds = bot . inventory . items ( ) . find ( item => item . name === seedType ) ;
if ( ! seeds ) {
log ( bot , ` No ${ seedType } to plant. ` ) ;
return false ;
}
await bot . equip ( seeds , 'hand' ) ;
await bot . placeBlock ( block , new Vec3 ( 0 , - 1 , 0 ) ) ;
log ( bot , ` Planted ${ seedType } at x: ${ x . toFixed ( 1 ) } , y: ${ y . toFixed ( 1 ) } , z: ${ z . toFixed ( 1 ) } . ` ) ;
}
return true ;
}
2024-04-19 14:02:30 -05:00
export async function activateNearestBlock ( bot , type ) {
/ * *
* Activate the nearest block of the given type .
* @ param { MinecraftBot } bot , reference to the minecraft bot .
* @ param { string } type , the type of block to activate .
* @ returns { Promise < boolean > } true if the block was activated , false otherwise .
* @ example
* await skills . activateNearestBlock ( bot , "lever" ) ;
* * * /
let block = world . getNearestBlock ( bot , type , 16 ) ;
if ( ! block ) {
log ( bot , ` Could not find any ${ type } to activate. ` ) ;
return false ;
}
if ( bot . entity . position . distanceTo ( block . position ) > 4.5 ) {
let pos = block . position ;
bot . pathfinder . setMovements ( new pf . Movements ( bot ) ) ;
await bot . pathfinder . goto ( new pf . goals . GoalNear ( pos . x , pos . y , pos . z , 4 ) ) ;
}
await bot . activateBlock ( block ) ;
log ( bot , ` Activated ${ type } at x: ${ block . position . x . toFixed ( 1 ) } , y: ${ block . position . y . toFixed ( 1 ) } , z: ${ block . position . z . toFixed ( 1 ) } . ` ) ;
return true ;
}