plugins
This commit is contained in:
@ -54,6 +54,7 @@ class CJbot{
|
||||
this.autoReConnect = 'autoConnect' in args ? args.autoReConnect : true;
|
||||
this.autoConnect = 'autoConnect' in args ? args.autoConnect : true;
|
||||
|
||||
|
||||
// If we want the be always connected, kick off the function to auto
|
||||
// reconnect
|
||||
if(this.autoReConnect) this.__autoReConnect()
|
||||
@ -74,8 +75,8 @@ class CJbot{
|
||||
// If an error happens before the login event, toss an error back to
|
||||
// the caller of the function
|
||||
let onError = this.bot.on('error', (m)=>{
|
||||
console.log(this.name, m.toString())
|
||||
reject(m)
|
||||
console.log('ERROR CJbot.connect on error:', this.name, m.toString());
|
||||
reject(m);
|
||||
})
|
||||
|
||||
// If the connection ends before the login event, toss an error back
|
||||
@ -87,9 +88,10 @@ class CJbot{
|
||||
});
|
||||
|
||||
// When the bot is ready, return to the caller success
|
||||
this.bot.on('login', ()=>{
|
||||
this.__onReady()
|
||||
resolve()
|
||||
this.bot.on('spawn', async()=>{
|
||||
console.log('CJbot.connect on spawn')
|
||||
this.__onReady();
|
||||
resolve();
|
||||
});
|
||||
|
||||
// Set a timer to try to connect again in 30 seconds if the bot is
|
||||
@ -123,20 +125,26 @@ class CJbot{
|
||||
|
||||
// Add the listeners to the bot. We do this so if the bot loses
|
||||
// connection, the mineflayer instance will also be lost.
|
||||
this.isReady = true;
|
||||
|
||||
this.__error();
|
||||
this.__startListeners();
|
||||
|
||||
// Call the internal listeners when the bot is ready
|
||||
for(let callback of this.listeners.onReady || []){
|
||||
console.log('calling listener', callback);
|
||||
await callback.call(this);
|
||||
callback.call(this);
|
||||
}
|
||||
|
||||
this.isReady = true;
|
||||
this.__error();
|
||||
console.log('Bot is ready', this.bot.entity.username, this.username);
|
||||
|
||||
// Start chat listeners
|
||||
this.__listen();
|
||||
|
||||
// this.bot.on('path_update', (...args)=>{ console.log('EVENT path_update', args) })
|
||||
// this.bot.on('goal_updated', (...args)=>{ console.log('EVENT goal_updated', args) })
|
||||
// this.bot.on('path_reset', (...args)=>{ console.log('EVENT path_reset', args) })
|
||||
// this.bot.on('path_stop', (...args)=>{ console.log('EVENT path_stop', args) })
|
||||
|
||||
|
||||
}catch(error){
|
||||
console.error('minecraft.js | __onReady | ', this.name, ' ', error);
|
||||
@ -144,6 +152,7 @@ class CJbot{
|
||||
|
||||
__startListeners(){
|
||||
for(let event in this.listeners){
|
||||
console.log('__adding listeners', event)
|
||||
for(let callback of this.listeners[event]){
|
||||
this.bot.on(event, callback);
|
||||
}
|
||||
@ -163,10 +172,26 @@ class CJbot{
|
||||
else this.bot.on(event, callback);
|
||||
}
|
||||
|
||||
return event === 'onReady' ? true : ()=> this.bot.off(listener, callback);
|
||||
return ()=> this.off(event, callback);
|
||||
}
|
||||
|
||||
// todo; add .off wrapper
|
||||
// Remove listener for events
|
||||
off(event, callback) {
|
||||
console.log('off', event, callback)
|
||||
if (!this.listeners[event]) return false;
|
||||
|
||||
const index = this.listeners[event].indexOf(callback);
|
||||
if (index === -1) return false;
|
||||
|
||||
this.listeners[event].splice(index, 1);
|
||||
|
||||
// If bot is ready, also remove from the Mineflayer bot
|
||||
if (this.isReady) {
|
||||
this.bot.off(event, callback);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Listen for ending events and call connect again
|
||||
__autoReConnect(){
|
||||
@ -207,6 +232,33 @@ class CJbot{
|
||||
}
|
||||
}
|
||||
|
||||
/* Plugins */
|
||||
|
||||
static plungins = {};
|
||||
|
||||
static pluginAdd(cls){
|
||||
this.plungins[cls.name] = cls
|
||||
}
|
||||
|
||||
plunginsLoaded = {};
|
||||
|
||||
async pluginLoad(pluginName, opts){
|
||||
console.log('CJbot.pluginLoad', pluginName)
|
||||
let plugin = new this.constructor.plungins[pluginName]({...opts, bot:this})
|
||||
await plugin.init();
|
||||
this.plunginsLoaded[pluginName] = plugin;
|
||||
}
|
||||
|
||||
async pluginUnload(name){
|
||||
console.log('CJbot.pluginUnload', name)
|
||||
if(this.plunginsLoaded[name]){
|
||||
await this.plunginsLoaded[name].unload();
|
||||
delete this.plunginsLoaded[name];
|
||||
console.log('CJbot.pluginUnload', name, 'done');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Chat and messaging*/
|
||||
|
||||
__listen(){
|
||||
@ -277,10 +329,9 @@ class CJbot{
|
||||
|
||||
async say(...messages){
|
||||
for(let message of messages){
|
||||
console.log('next chat time:', this.nextChatTime > Date.now(), Date.now()+1, this.nextChatTime-Date.now()+1);
|
||||
// console.log('next chat time:', this.nextChatTime > Date.now(), Date.now()+1, this.nextChatTime-Date.now()+1);
|
||||
(async (message)=>{
|
||||
if(this.nextChatTime > Date.now()){
|
||||
console.log('am sleeping');
|
||||
await sleep(this.nextChatTime-Date.now()+1)
|
||||
}
|
||||
this.bot.chat(message);
|
||||
@ -357,6 +408,8 @@ class CJbot{
|
||||
return this.bot.players;
|
||||
}
|
||||
|
||||
/* Actions */
|
||||
|
||||
__blockOrVec(thing){
|
||||
if(thing instanceof Vec3.Vec3) return this.bot.blockAt(thing);
|
||||
if(thing.constructor && thing.constructor.name === 'Block') return thing;
|
||||
@ -364,31 +417,83 @@ class CJbot{
|
||||
throw new Error('Not supported block identifier');
|
||||
}
|
||||
|
||||
async _goTo(block, range=2){
|
||||
block = this.__blockOrVec(block);
|
||||
|
||||
return await this.bot.pathfinder.goto(new GoalNear(...block.position.toArray(), range));
|
||||
}
|
||||
|
||||
goTo(options){
|
||||
return new Promise(async(resolve, reject)=>{
|
||||
|
||||
let range = options.range || 2;
|
||||
|
||||
try{
|
||||
await this._goTo(options.where, range)
|
||||
return resolve();
|
||||
}catch(error){
|
||||
if(options.reTry) return reject('Action can not move to where')
|
||||
await this._goTo(options, true);
|
||||
findBlockBySign(text){
|
||||
return this.bot.findBlock({
|
||||
useExtraInfo: true,
|
||||
maxDistance: 64,
|
||||
matching: (block)=> {
|
||||
if(block.name.includes('sign') && block.signText.includes(text)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
findChestBySign(text){
|
||||
return this.bot.findBlock({
|
||||
point: this.findBlockBySign(text).position,
|
||||
// maxDistance: 1,
|
||||
useExtraInfo: true,
|
||||
matching: block => block.name === 'chest'
|
||||
});
|
||||
}
|
||||
|
||||
isWithinRange(target, range=2) {
|
||||
const botPos = this.bot.entity.position;
|
||||
const distance = botPos.distanceTo(target);
|
||||
|
||||
return distance <= range+.9;
|
||||
}
|
||||
|
||||
async _goTo(block, range=2){
|
||||
try{
|
||||
}catch(error){
|
||||
if(error.message === 'Not supported block identifier'){
|
||||
console.log('found block error')
|
||||
await sleep(1000);
|
||||
block = this.__blockOrVec(block);
|
||||
}
|
||||
console.log('other', error)
|
||||
}
|
||||
|
||||
try{
|
||||
}catch(error){
|
||||
if(error.name === 'GoalChanged') return await this._goTo(block, range);
|
||||
console.log('error in _goTo', error.name, '|', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
async goTo(options) {
|
||||
let range = options.range || 2;
|
||||
let block = this.__blockOrVec(options.where);
|
||||
|
||||
while(!this.isWithinRange(this.__blockOrVec(options.where).position, range)){
|
||||
try{
|
||||
if(this.bot.pathfinder.isMoving()){
|
||||
await sleep(500);
|
||||
console.log('the bot is moving...')
|
||||
continue;
|
||||
}
|
||||
await this.bot.pathfinder.goto(
|
||||
new GoalNear(...block.position.toArray(), range)
|
||||
);
|
||||
}catch(error){
|
||||
await sleep(500);
|
||||
console.log('CJbot.goTo while loop error:', error)
|
||||
// await this.bot.pathfinder.setGoal(null);
|
||||
await this.bot.pathfinder.stop();
|
||||
await sleep(500);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
async goToReturn(options){
|
||||
let here = this.bot.entity.position;
|
||||
let hereYaw = this.bot.entity.yaw
|
||||
await this.goTo(options);
|
||||
|
||||
return async () =>{
|
||||
await this.goTo({where: here, range: 0}, true);
|
||||
await sleep(500);
|
||||
@ -396,7 +501,6 @@ class CJbot{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async __nextContainerSlot(window, item) {
|
||||
let firstEmptySlot = false;
|
||||
|
||||
@ -418,27 +522,124 @@ class CJbot{
|
||||
async openContainer(block){
|
||||
let count = 0;
|
||||
block = this.__blockOrVec(block);
|
||||
let window;
|
||||
|
||||
while(!this.bot.currentWindow){
|
||||
let window = this.bot.openContainer(block);
|
||||
await sleep(1500);
|
||||
try{
|
||||
window = await this.bot.openContainer(block);
|
||||
}catch(error){
|
||||
if(!error.message.includes('Event windowOpen did not fire within timeout')) throw error;
|
||||
}
|
||||
if(this.bot.currentWindow?.title){
|
||||
break;
|
||||
}
|
||||
this.bot.removeAllListeners('windowOpen');
|
||||
this.bot.removeAllListeners('windowOpen');
|
||||
await sleep(1500);
|
||||
|
||||
if(count++ == 3) throw 'Block wont open';
|
||||
}
|
||||
|
||||
return this.bot.currentWindow;
|
||||
}
|
||||
|
||||
async openCraftingTable(block){
|
||||
let count = 0;
|
||||
block = this.__blockOrVec(block);
|
||||
this.bot.activateBlock(block);
|
||||
let window = await this.once('windowOpen');
|
||||
|
||||
// while(!this.bot.currentWindow){
|
||||
// try{
|
||||
// if(this.bot.currentWindow?.title){
|
||||
// break;
|
||||
// }
|
||||
// this.bot.removeAllListeners('windowOpen');
|
||||
|
||||
// if(count++ == 3) throw 'Block wont open';
|
||||
|
||||
// }catch(error){
|
||||
// console.error('ERROR in CJbot.openCraftingTable:', error)
|
||||
// }
|
||||
// }
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
|
||||
async checkItemsFromContainer(containerBlock, itemName, count){
|
||||
let currentSlot = 0;
|
||||
let foundCount = 0;
|
||||
let window = await this.openContainer(containerBlock);
|
||||
|
||||
for(let slot of window.slots){
|
||||
if(currentSlot++ === window.inventoryStart) break;currentSlot
|
||||
if(!slot) continue;
|
||||
if(slot.name === itemName) foundCount += slot.count;
|
||||
}
|
||||
|
||||
await this.bot.closeWindow(window);
|
||||
if(foundCount >= count) return true;
|
||||
}
|
||||
|
||||
async getItemsFromChest(containerBlock, itemName, count){
|
||||
let window = await this.openContainer(containerBlock);
|
||||
await sleep(500);
|
||||
// console.log('item id', this.mcData.itemsByName[itemName], this.mcData)
|
||||
await window.withdraw(this.mcData.itemsByName[itemName].id, null, count);
|
||||
await this.bot.closeWindow(window);
|
||||
}
|
||||
|
||||
async getFullShulkersFromChest(chestBlock, item) {
|
||||
const fullShulkers = [];
|
||||
|
||||
let window = await this.openContainer(chestBlock);
|
||||
|
||||
|
||||
let currentSlot = 0;
|
||||
for(let slot of window.slots){
|
||||
if(currentSlot++ === window.inventoryStart) break;
|
||||
if(!slot) continue;
|
||||
|
||||
// if(!slot || slot.name !== 'shulker_box') continue;
|
||||
console.log('slot:', slot)
|
||||
if(slot.nbt){
|
||||
// console.log(slot.nbt)
|
||||
console.log('BlockEntityTag:', slot.nbt.value.BlockEntityTag.value.Items.value.value)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* // Get the inventory of the chest block
|
||||
const chestInventory = chestBlock.getInventory();
|
||||
|
||||
// Iterate through the chest's inventory
|
||||
chestInventory.forEach((slot, index) => {
|
||||
// Check if the slot contains a shulker box
|
||||
if (slot && slot.type === 'shulker_box') {
|
||||
// Retrieve the shulker's inventory
|
||||
const shulkerInventory = slot.getInventory();
|
||||
|
||||
// Check if the shulker is full of the specified item
|
||||
const isFull = shulkerInventory.every(shulkerSlot => {
|
||||
console.log('shulkerSlot', shulkerSlot)
|
||||
return shulkerSlot && shulkerSlot.id === item.id && shulkerSlot.count === 64; // Assuming max stack size is 64
|
||||
});
|
||||
|
||||
// If full, add the shulker box to the list
|
||||
if (isFull) {
|
||||
fullShulkers.push(slot);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return fullShulkers;*/
|
||||
}
|
||||
|
||||
async dumpToChest(block, blockName, amount) {
|
||||
|
||||
let window = await this.openContainer(block);
|
||||
|
||||
let items = window.slots.slice(window.inventoryStart).filter(function(item){
|
||||
let items = window.slots.slice(window.inventoryStart).filter(function(item){
|
||||
if(!item) return false;
|
||||
if(blockName && blockName !== item.name) return false;
|
||||
return true;
|
||||
|
Reference in New Issue
Block a user