const env = require ( "dotenv-packed" ) . parseEnv ( ) . parsed
const fs = require ( 'fs' ) ;
const cfg = {
admin : process . env . MINECRAFT _PLAYER _ADMIN || env . MINECRAFT _PLAYER _ADMIN || console . warn ( "main: bot admin user not provided" ) ,
mods : process . env . MINECRAFT _PLAYER _MODS || env . MINECRAFT _PLAYER _MODS || [ ] , // json array,
stateMachines : { }
}
const mineflayer = require ( "mineflayer" ) ;
// const { createGetAccessor } = require('typescript');
const options = ! isNaN ( parseInt ( process . argv [ 3 ] ) ) && parseInt ( process . argv [ 3 ] ) > 1e2 ?
{
host : process . argv [ 2 ] || process . env . MINECRAFT _HOST || env . MINECRAFT _HOST || 'localhost' , // Change this to the ip you want.
port : parseInt ( process . argv [ 3 ] ) || process . env . MINECRAFT _PORT || env . MINECRAFT _PORT // || 58471,
}
:
{
host : process . argv [ 2 ] || process . env . MINECRAFT _HOST || env . MINECRAFT _HOST || 'localhost' , // Change this to the ip you want.
username : process . argv [ 3 ] || process . env . MINECRAFT _USER || env . MINECRAFT _USER ,
password : process . argv [ 4 ] || process . env . MINECRAFT _PASS || env . MINECRAFT _PASS ,
// port: process.argv[5] || process.env.MINECRAFT_PORT || 58471,
}
const bot = mineflayer . createBot ( options )
cfg . botOptions = options
let plugins = { }
function loadplugin ( pluginname , pluginpath = './plugins/' + pluginname ) {
try {
plugins [ pluginname ] = require ( pluginpath )
plugins [ pluginname ] . load ( cfg )
} catch ( error ) {
if ( error . code == 'MODULE_NOT_FOUND' ) {
console . warn ( 'plugin not used:' , pluginpath )
} else if ( plugins [ pluginname ] && ! plugins [ pluginname ] . load ) {
unloadplugin ( pluginname , pluginpath )
} else {
console . error ( error )
}
}
}
function unloadplugin ( pluginname , pluginpath = './plugins/' + pluginname ) {
const plugin = require . resolve ( pluginpath )
try {
if ( plugin && require . cache [ plugin ] ) {
// `unload()` isn't exported sometimes,
// when plugin isn't properly loaded
require . cache [ plugin ] . exports ? . unload ? . ( )
delete plugins [ pluginname ]
delete require . cache [ plugin ]
}
} catch ( error ) {
console . error ( error )
}
}
function reloadplugin ( event , filename , pluginpath = './plugins/' ) {
if ( ! /\.js$/ . test ( filename ) ) { return }
filename = filename . replace ( "\\" , "/" ) // windows
if ( ! cfg . fsTimeout ) {
console . info ( event , filename )
const fullpluginpath = pluginpath + filename
const pluginname = ( filename . split ( ".js" ) [ 0 ] ) . replace ( /\/.+/ , "" )
pluginpath = pluginpath + pluginname
const hassubplugin = fullpluginpath . replace ( /\.js$/ , "" ) !== pluginpath
const check = Object . keys ( cfg . plugins )
console . info ( ` reload file: ./lib/ ${ fullpluginpath } ` )
const plugin = require . resolve ( fullpluginpath )
if ( plugin && require . cache [ plugin ] ) {
// console.debug(Object.keys(cfg.plugins))
unloadplugin ( pluginname )
console . assert ( Object . keys ( cfg . plugins ) . length == check . length - 1 , "plugin not removed, potential memory leak" )
if ( hassubplugin ) {
console . info ( "reload: also unloading sub" )
unloadplugin ( pluginname , fullpluginpath )
}
}
loadplugin ( pluginname )
if ( Object . keys ( cfg . plugins ) . length != check . length ) {
// If left < right :
// - new plugin that's not registered in cfg.plugins, so added
// - rename, so old wasn't removed
// If left > right :
// - error in file (syntax, missing load()), so was not reloaded
console . warn ( "plugin count mismatch" , check . length , Object . keys ( cfg . plugins ) . length , Object . keys ( cfg . plugins ) )
}
cfg . fsTimeout = setTimeout ( function ( ) { cfg . fsTimeout = null } , 2000 ) // give 2 seconds for multiple events
}
// console.log('file.js %s event', event)
}
fs . watch ( './lib/plugins' , { recursive : true } , reloadplugin )
cfg . bot = bot
// TODO better name, or switch to array
cfg . botAddressPrefix = '!'
cfg . quiet = true
// == actually do stuff
bot . once ( "spawn" , ( ) => {
plugins = {
command : require ( './plugins/command' ) ,
informer : require ( './plugins/informer' ) ,
inventory : require ( './plugins/inventory' ) ,
finder : require ( './plugins/finder' ) ,
mover : require ( './plugins/mover' ) ,
sleeper : require ( './plugins/sleeper' ) ,
eater : require ( './plugins/eater' ) ,
armor : require ( './plugins/armor' ) ,
guard : require ( './plugins/guard' ) ,
// miner: require('./plugins/miner.js'),
statemachine : require ( './plugins/statemachine' ) ,
}
cfg . plugins = plugins
// cfg.botAddressPrefix = ${bot.username.substr(-2,2)}
cfg . botAddressRegex = new RegExp ( ` ^ ${ bot . username } :? (/| ${ cfg . botAddressPrefix } .+) ` )
// FIXME leaks every load, so adding here instead of command.js to load only once
bot . addChatPattern ( "web" , /\[WEB\] (\[.+\])?\s*([\w.]+): (.+)/ , { parse : true } )
for ( const plugin of Object . values ( plugins ) ) {
try {
plugin . load ( cfg )
} catch ( error ) {
console . warn ( error )
}
}
} )
bot . on ( "death" , ( ) => {
bot . pathfinder && bot . pathfinder . setGoal ( null )
// plugins.guard.unload()
} )
// bot.on("respawn", () => {
// // setTimeout(plugins.guard.load, 2000)
// })