mc-bot-town-2/nodejs/model/minecraft.js
2022-09-25 14:01:47 -04:00

273 lines
5.9 KiB
JavaScript

'use strict';
const {sleep} = require('../utils');
const mineflayer = require('mineflayer');
class CJbot{
isReady = false;
listeners = {};
nextChatTime = 1500;
commandLock = false;
commandCollDownTime = 1500;
commands = {};
combatTag = false;
doLogOut = false;
constructor(args){
this.username = args.username;
this.password = args.password;
this.host = args.host;
this.auth = args.auth || 'microsoft';
this.version = args.version || '1.18.2';
this.autoReConnect = 'autoConnect' in args ? args.autoReConnect : true;
this.autoConnect = 'autoConnect' in args ? args.autoConnect : true;
if(this.autoConnect){
console.log('connecting', this.username, this.autoConnect)
this.connect();
}
if(this.autoReConnect){
this.__autoReConnect()
}
}
connect(){
return new Promise((resolve, reject) =>{
this.bot = mineflayer.createBot({
host: this.host,
username: this.username,
password: this.password,
version: this.version,
auth: this.auth,
});
// this.bot.on('message', (m)=> console.log(m.toString()))
this.bot.on('error', (m)=>{
console.log(this.bot.version, m.toString())
reject(m)
})
this.bot.on('end', reason =>{
console.log('Connection ended:', reason)
this.isReady = false
}
);
this.bot.on('login', ()=>{
this.__onReady()
resolve()
});
});
}
once(event){
return new Promise((resolve, reject)=> this.bot.once(event, resolve));
}
async __onReady(){
this.__startListeners();
console.log('listeners', this.listeners.onReady)
for(let callback of this.listeners.onReady || []){
console.log('calling listener', callback)
await callback(this)
}
this.isReady = true;
this.__error()
console.log('Bot is ready', this.bot.entity.username, this.username);
// Start chat listeners
this.__listen();
}
__startListeners(){
for(let event in this.listeners){
for(let callback of this.listeners[event]){
this.bot.on(event, callback)
}
}
}
on(event, callback){
if(!this.listeners[event]) this.listeners[event] = [];
this.listeners[event].push(callback);
if(this.isReady){
if(event === 'onReady') callback(this);
else this.bot.on(event, callback);
}
return event === 'onReady' ? true : ()=> this.bot.off(listener, callback);
}
__autoReConnect(){
console.log('auto connect function')
this.on('end', (reason)=>{
console.error('MC on end', reason)
this.connect()
});
this.bot.on('kick', console.error)
this.on('error', (error)=>{
console.error('MC on error', error);
this.connect();
});
}
__error(){
this.bot.on('error', (error)=>{
console.error(`ERROR!!! MC bot ${this.username} on ${this.host} had an error:\n`, error)
});
}
getPlayers(){
for (let [username, value] of Object.entries(this.bot.players)){
value.lvl = Number(value.displayName.extra[0].text)
}
return this.bot.players;
}
/* Chat and messaging*/
__listen(){
this.bot.on('chat', (from, message)=>{
// Ignore messages from this bot
if(from === this.bot.entity.username) return;
// Filter messages to this bot
if(message.startsWith(this.bot.entity.username)){
this.__doCommand(
from,
message.replace(`${this.bot.entity.username} ` , ' ').trim()
)
}
});
this.bot.on('whisper', (from, message)=>{
this.__doCommand(
from,
message.replace(`${this.bot.entity.username} ` , ' ').trim()
)
});
this.bot.on('message', (message, type)=>{
if(message.toString().includes(' invited you to teleport to him.')){
// teleport invite
// console.log('ChatBot on message', message.toString())
this.__doCommand(message.toString().split(' ')[0], '.invite');
}
if(message.toString().includes('You are combat tagged by')){
try{
this.combatTag = true;
console.log('was attacked by')
let attacker = message.toString().split('. ')[0].replace('You are combat tagged by ', '')
console.log('was attacked by', attacker)
// teleport invite
this.whisper(attacker, 'Please do not attack me, I am a bot.')
}catch(error){
console.log('error!!!!!!', error)
}
}
if(message.toString().includes('You are no longer in combat. You may now logout.')){
this.combatTag = false
if(this.doLogOut){
this.quit()
}
}
});
}
quit(force){
if(!this.combatTag){
this.bot.quit();
}else{
console.log('stoped logout due to combatTag')
this.doLogOut = true;
}
}
__chatCoolDown(){
return Math.floor(Math.random() * (3000 - 1500) + 1500);
}
async say(...messages){
for(let message of messages){
if(this.nextChatTime > Date.now()){
await sleep(this.nextChatTime-Date.now()+1)
}
this.bot.chat(message);
this.nextChatTime = Date.now() + this.__chatCoolDown();
}
}
async whisper(to, ...messages){
await this.say(...messages.map(message=>`/msg ${to} ${message}`));
}
/* Commands */
async __unLockCommand(time){
await sleep(this.commandCollDownTime);
this.commandLock = false;
}
__reduceCommands(from){
return Object.keys(this.commands).filter(command =>{
if (this.commands[command].allowed && !this.commands[command].allowed.includes(from)) return false;
return true;
});
}
async __doCommand(from, command){
if(this.commandLock){
this.whisper(from, `cool down, try again in ${this.commandCollDownTime/1000} seconds...`);
return ;
}
let [cmd, ...parts] = command.split(/\s+/);
if(this.__reduceCommands(from).includes(cmd)){
this.commandLock = true;
try{
await this.commands[cmd].function.call(this, from, ...parts);
}catch(error){
this.whisper(from, `The command encountered an error.`);
console.error(`Chat command error on ${cmd} from ${from}\n`, error);
}
this.__unLockCommand();
}else{
this.whisper(from, `I dont know anything about ${cmd}`);
}
}
addCommand(name, obj){
if(this.commands[name]) return false;
this.commands[name] = obj;
}
}
module.exports = {CJbot};