//Load required classes. const { Servers } = require('alta-jsapi'); const { WebsocketBot } = require('att-bot-core'); const { BasicWrapper } = require('att-websockets'); const Discord = require('discord.js'); const moment = require('moment'); const sha512 = require('crypto-js/sha512'); const fs = require('fs'); const alta_jsapi = require('alta-jsapi'); //Local classes const Player = require('./src/player.js'); const Subscriptions = require('./src/subscriptions.js'); const commands = require('./src/discordcmds.js') const managers = require('./src/managers.js'); //Load information from credentials and config const { username, password, botToken } = require("./credentials"); const { targetServers, showAllServers, blacklistServers, discordPrefix, discordChannels, discordRoles } = require("./config"); //readline stuffs const readline = require('readline'); const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); //NeDB var Datastore = require('nedb'); var players = new Datastore({ filename : 'data/players.db', autoload: true }); var kills = new Datastore({ filename : 'data/playerkills.db', autoload: true }); var chunkHistory = new Datastore({ filename : 'data/chunkhistory.db', autoload: true }); var spawnables = new Datastore({ filename : 'data/spawnables.db', autoload: true }); players.ensureIndex({ fieldName: 'id', unique: 'true' }); players.persistence.setAutocompactionInterval( 129600 ); spawnables.ensureIndex({ fieldName: 'hash', unique: 'true' }); //Vars var playername = username; var botConnection; var pendingCommandList = []; //Some utility helper functions and prototypes function ts() { return "["+ moment().format("h:mm:ss A") +"] " } function strrep( str, n ) { if ( n < 1 ) return ''; var result = str; while( n-- > 0 ) { result += str; } return result; } // Database helpers function insertHandler( err, doc ) { if ( err ) { console.log( err ); } } function updateHandler( err, rows ) { if ( err ) { console.log( err ); } } function convertPassToHash( username, password, botToken ) { // The SHA512 hash generated by crypto-js/sha512 will be 128 characters if ( password.length !== 128 ) { console.log( "Plaintext password encountered, converting to SHA512 hash for permanent storage" ); newPass = alta_jsapi.Sessions.hashPassword(password) newFile = { "username" : username, "password" : newPass, "botToken": botToken }; fs.writeFile('./credentials.json', JSON.stringify( newFile, null, 4 ), function( err ) { if ( err ) { console.log( err ); } else { console.log( "New credentials.json saved" ); } }); password = newPass; } return password; } //Run the program main(); async function main() { console.log( ts() + "[BorisBot: Discord Edition] is Starting" ); // Convert the password to a hash if necessary var mpassword = convertPassToHash( username, password, botToken ); // Players in database //players.find({}).exec( function( err, docs ) { console.log( docs ); }); //Connect to discord const discord = new Discord.Client(); await new Promise( resolve => { discord.on('ready', resolve); discord.login(botToken); }); //Discord command and message management (todo: move to own lib) discord.on('message', message => { if ( message.content.length > 0 && message.content.startsWith( discordPrefix ) ) { var tmessage = message.content.substring(discordPrefix.length).trim(); var args = splitArgs( tmessage ); if ( args && args.length >= 1 ) { var command = args.shift(); var commandFunction = commands[command]; if (!!commandFunction) { commandFunction(message, args, tmessage); } } } }); //Alta Login const bot = new WebsocketBot(); //Use a hashed password, SHA512 await bot.loginWithHash(username, mpassword); //Run the bot. //When any of the 'targetServers' are available, a connection is automatically created. var subs = new Subscriptions( discordChannels, players, kills, chunkHistory ); alta_jsapi.Sessions.loginWithUsername(username, mpassword); var targetServers = [] serverquery() function serverquery() { rl.question('Server? > ', (serverans) => //Outputs 'Server? > ' to allow the user to input one of the below results { (async () => { servers = await alta_jsapi.Servers.getConsoleServers() for(i=0; i targetServers.includes(test.id), async (server, connection) => { var wrapper = new BasicWrapper(connection); botConnection = { "connection" : connection, "wrapper" : wrapper } console.log( ts() +"loading inital players" ); for ( var i in server.online_players ) { let oplayer = server.online_players[i]; subs.PlayerJoined( discord, { "user": { "id": oplayer.id, "username": oplayer.username } }); } //Subscriptions await wrapper.subscribe("PlayerJoined", data => { subs.PlayerJoined( discord, data ) }); await wrapper.subscribe("PlayerLeft", data => { subs.PlayerLeft( discord, data ); }); await wrapper.subscribe("PlayerKilled", data => { subs.PlayerKilled( discord, data ); }); await wrapper.subscribe("TradeDeckUsed", data => { subs.TradeDeckUsed( discord, data ); }); await wrapper.subscribe("CreatureKilled", data => { subs.CreatureKilled( discord, data ); }); await wrapper.subscribe("PlayerMovedChunk", data => { subs.PlayerMovedChunk( discord, data ); }); await wrapper.subscribe("TraceLog", data => { if (message.content.startsWith("!")) { say("Working on pleb commands shut it") } // Admin Only /////////////////////////////////////////////////////////////////// // Admin commands are preceeded by an exclamation mark to avoid accidentally doing stuff. else if (message.content.startsWith("!!")) { var TEMPmessage = message.content.replace(/[,\/#!$%\^&\*;:{}=\-_`'~?()]/g,"") originalMessageAsAnArray = TEMPmessage.split(' '); // Make sure the user is CJ or Poi. if (message.author.discriminator.match("8147")) { // List possible commands. Will explan on this later. if (hazWerds("command", "list") == "Y") { say('**Current commands:** \n!teleport [PLAYER] to [PLAYER]\n!broadcast [TIME IN SECONDS] [MESSAGE WITH NO QUOTES] (Still working on this)') } // Broadcast a message to all players. else if (hazWerds("broadcast") == "Y") { originalMessageAsAnArray.shift() TEMPduration = originalMessageAsAnArray[0] originalMessageAsAnArray.shift() TEMPmessage = originalMessageAsAnArray.join(" ") try { wrapper.send('player message * "' + TEMPmessage + '" ' + TEMPduration) say('SENT: player message * "' + TEMPmessage + '" ' + TEMPduration) } catch(err) {main()} } // Teleport one player to another. else if (hazWerds("teleport", "to") == "Y") { try {wrapper.send("player teleport " + originalMessageAsAnArray[1] + " " + originalMessageAsAnArray[3]) say(originalMessageAsAnArray[1] + " should have been teleported to " + originalMessageAsAnArray[3] + ".")} catch(err) {main()} } // Just send it to the server directly as a command. else { wrapper.send(TEMPmessage) } } } } ); } ) } )() } ) } }