let bot
let mcData
let quiet
// import v from 'vec3'
const v = require ( 'vec3' )
let cfg = {
info : {
quiet : quiet ,
recentCommand : null ,
} ,
// to satisfy typescript
quiet : null ,
bot : bot
}
var RelativePosEnum
( function ( RelativePosEnum ) {
RelativePosEnum [ RelativePosEnum [ "feet" ] = 0 ] = "feet"
RelativePosEnum [ RelativePosEnum [ "standing" ] = 1 ] = "standing"
RelativePosEnum [ RelativePosEnum [ "head" ] = 2 ] = "head"
RelativePosEnum [ RelativePosEnum [ "looking" ] = 3 ] = "looking"
RelativePosEnum [ RelativePosEnum [ "infront" ] = 4 ] = "infront"
RelativePosEnum [ RelativePosEnum [ "behind" ] = 5 ] = "behind"
} ) ( RelativePosEnum || ( RelativePosEnum = { } ) )
function relPosToBlock ( entity , relPos ) {
let pos
if ( ! ( relPos in RelativePosEnum ) ) return console . warn ( "info: not a relative position:" , relPos )
relPos = typeof relPos === "number" ? RelativePosEnum [ relPos ] : relPos
switch ( relPos ) {
case "feet" :
pos = entity . position ;
break
case "standing" :
pos = entity . position . offset ( 0 , - 1 , 0 )
break
// todo use CARDINAL directions api from pathfinder
// case "behind":
// entity.yaw
// pos = entity.position
// break
// case "front":
// case "infront":
// pos = entity.position
// break
case "head" :
pos = entity . position . offset ( 0 , 1.85 , 0 )
break
case "looking" :
if ( entity === bot . entity ) {
return bot . blockAtCursor ( )
// return bot.blockInSight(128, 128)
}
default :
quiet || bot . chat ( ` info: pos ' ${ relPos } ' not implemented ` )
break
}
if ( pos ) {
// nearest block
return bot . blockAt ( pos )
}
}
function isVec3 ( vec ) {
return vec ? . length === 3 || vec . x && vec . y && vec . z
}
function block ( entity = bot . entity , pos = entity ? . position ? . offset ( 0 , - 1 , 0 ) ) {
console . assert ( pos || entity )
const block = isVec3 ( pos ) ? bot . blockAt ( v ( pos ) )
: typeof pos === "string" ? relPosToBlock ( entity , RelativePosEnum [ pos ] ) : pos
console . log ( block , block ? . getProperties && block . getProperties ( ) )
if ( ! block ) {
quiet || bot . chat ( "empty block" )
return block
}
bot . lookAt ( block ? . position )
let info = [ block . type , block . name ]
if ( block . metadata ) info . push ( Object . entries ( block . getProperties ( ) ) )
quiet || bot . chat ( info . join ( ": " ) )
}
function item (
entity = bot . entity ,
slot = entity . heldItem
) {
const item = typeof slot === "number" ?
bot . inventory . slots [ slot + bot . QUICK _BAR _START ] :
slot
console . log ( "info item:" , item )
if ( ! item ) {
quiet || bot . chat ( "no item" )
return item
}
let info = [ item . type , item . name , item . count ]
if ( item . metadata ) info . push ( "meta: " + item . metadata . length )
if ( item . nbt ) {
info . push ( compound _value ( item . nbt ) )
}
quiet || bot . chat ( info . join ( "; " ) )
function compound _value ( obj ) {
if ( typeof obj . value == "object" ) {
return compound _value ( obj . value )
} else if ( obj . value ) {
return obj . value
} else if ( typeof obj == "object" ) {
const keys = Object . keys ( obj )
return keys . map ( key => {
return ` ${ key } : ${ compound _value ( obj [ key ] ) } `
} ) ;
} else {
return obj
}
}
return item
}
function entity ( name = bot . nearestEntity ( ) ) {
const entity = typeof name === "string" ? ( name = name . toLowerCase ( ) ) && bot . nearestEntity ( ( entity ) => {
const enames = [ entity . username ? . toLowerCase ( ) , entity . name , entity . displayName ? . toLowerCase ( ) ]
return enames . includes ( name )
} ) : name
console . log ( "info entity:" , entity )
if ( ! entity ) {
quiet || bot . chat ( "no entity" )
return entity
}
let info = [ entity . type , entity . username || entity . name ]
// TODO various info depending on the type of entity; player, villager, etc
if ( entity . metadata ) info . push ( "len: " + entity . metadata . length )
quiet || bot . chat ( info . join ( "; " ) )
return entity
}
function blockOrItemFromId ( num , quiet = cfg . info . quiet ) {
const block = mcData ? . blocks [ num ]
const item = mcData ? . items [ num ]
// const entity = mcData?.entities[num]
if ( block || item ) {
quiet || bot . chat (
( block && ` block: ${ block . name } , ` || "" )
+ ( item && ` item: ${ item . name } , ` || "" )
// + (entity && `entity: ${entity.name}, ` || "")
)
} else {
quiet || bot . chat ( "info: nonexistent block or item" )
}
return { block , item }
}
function command ( message _parts , player ) {
if ( message _parts . length > 0 ) {
cfg . info . recentCommand = message _parts
}
switch ( message _parts . length ) {
case 0 :
if ( cfg . info . recentCommand ) {
command ( cfg . info . recentCommand , player )
} else {
// TODO dispatch on instance of entity, block, etc..
// TODO have the logic inside the function or with a utility function
block ( )
}
break ;
case 1 :
switch ( message _parts [ 0 ] ) {
case "quiet" :
cfg . info . quiet = quiet = ! quiet ;
quiet || bot . chat ( ` info: ${ quiet ? "" : "not " } being quiet ` ) ;
break ;
case "i" :
case "item" :
item ( )
break
case "e" :
case "entity" :
entity ( )
break
case "me" :
block ( player )
break
case "b" :
case "block" :
block ( )
break
default :
const num = parseInt ( message _parts [ 0 ] )
if ( isFinite ( num ) ) {
blockOrItemFromId ( num )
} else {
quiet || bot . chat ( "info usage: `!info [me|i|e|b|<num>|quiet]`" )
}
break ;
}
break ;
case 2 :
switch ( message _parts [ 0 ] ) {
case "i" :
case "item" :
switch ( message _parts [ 1 ] ) {
case "me" :
item ( player )
break
default :
const slot = parseInt ( message _parts [ 1 ] )
slot && item ( undefined , slot )
break
}
break
case "b" :
case "block" :
switch ( message _parts [ 1 ] ) {
case "me" :
block ( player )
break
default :
if ( message _parts [ 1 ] in RelativePosEnum ) {
block ( undefined , message _parts [ 1 ] )
} else {
// or entity(message_parts[1]).position
console . log ( bot . players [ message _parts [ 1 ] ] )
quiet || bot . chat ( "info: not yet implemented" )
}
}
break
case "e" :
case "entity" :
default :
entity ( message _parts [ 1 ] )
break ;
}
break
case 4 :
switch ( message _parts [ 0 ] ) {
case "b" :
case "block" :
default :
block ( undefined , message _parts . slice ( 1 ) )
break ;
}
break ;
default :
cfg . quiet || bot . chat ( "info: unknown command" )
break ;
}
}
const load = ( config ) => {
config . info = cfg . info
cfg = config
bot = cfg . bot
mcData = bot . mcData || ( bot . mcData = require ( 'minecraft-data' ) ( bot . version ) )
}
const unload = ( ) => { }
module . exports = { load , unload , command , block , item , entity }