├── config.json ├── LICENSE ├── README.md └── index.js /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "token": "", 3 | "prefix": "a." 4 | } 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Agar.io discord bot 2 | 3 | # Agar.io discord bot 4 | 5 | > discord bot to create/check agar.io party servers. [invite link](https://discordapp.com/oauth2/authorize?client_id=603138922532438037&scope=bot&permissions=7232) 6 | 7 | ## 8 | 9 | ### !!! OUTDATED !!! 10 | 11 | ### How to use 12 | * create discord application [here](https://discordapp.com/developers/applications) 13 | * go to bot section and press add bot 14 | * copy your discord bot token to config.json 15 | * run the bot 16 | * invite the bot to your server using client id in general information you can use [this](https://discordapi.com/permissions.html) to generate invite link 17 | 18 | ### Commands 19 | 20 | **default prefix [ a. ]** 21 | 22 | * a.help 23 | * a.agar 24 | * a.ffa 25 | * a.exp 26 | * a.party 27 | * a.ping 28 | * a.invite 29 | 30 | ### Pictures 31 | 32 | ![Screenshot from 2019-10-02 21 50 27](https://user-images.githubusercontent.com/48287047/66076706-ab970b00-e55e-11e9-9b8e-9e6593ab27b7.png) 33 | ![Screenshot from 2019-10-02 21 47 59](https://user-images.githubusercontent.com/48287047/66076574-6bd02380-e55e-11e9-91cf-91d65f6d2411.png) 34 | ![Screenshot from 2019-10-02 21 48 10](https://user-images.githubusercontent.com/48287047/66076589-72f73180-e55e-11e9-9c76-67721e2d5602.png) 35 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const { Client, MessageEmbed } = require('discord.js'); 2 | const bot = new Client({ disableEveryone: true }); 3 | const { murmur2 } = require('murmurhash-js'); 4 | const request = require('request-promise'); 5 | const config = require('./config.json'); 6 | const WebSocket = require('ws'); 7 | require('colour'); 8 | 9 | let embed = new MessageEmbed(); 10 | let prefix = config.prefix; 11 | 12 | bot.on('ready', async () => { 13 | bot.user.setActivity(`${prefix}help`, { type: 'PLAYING' }); 14 | console.log('Ready'.green); 15 | let xclientkey = await request('https://agar.io/mc/agario.js'); 16 | let versionString = xclientkey.match(/(?<=versionString=")[^"]+/)[0]; 17 | const { groups: { protoVersion } } = /proto-version.+?"(?\d+.+?)"/gm.exec(xclientkey); 18 | let versionInt = parseInt(versionString.split('.')[0]) * 10000 + parseInt(versionString.split('.')[1]) * 100 + parseInt(versionString.split('.')[2]); 19 | let core = await request('https://agar.io/agario.core.js'); 20 | let protocolVersion = core.match(/d;..\(.,(\d+)\);/)[1]; 21 | global.protocolVersion = protocolVersion; 22 | global.protoVersion = protoVersion; 23 | global.versionInt = versionInt; 24 | update(); 25 | }); 26 | 27 | bot.on('message', async msg => { 28 | if (!msg.content.toLocaleLowerCase().startsWith(prefix)) return; 29 | if (msg.author.bot || msg.channel.type === 'dm') return; 30 | 31 | const args = msg.content.toLocaleLowerCase().substring(prefix.length).split(' '); 32 | 33 | switch (args[0].toLocaleLowerCase()) { 34 | 35 | case 'ping': 36 | embed = new MessageEmbed(); 37 | embed.addField('Bot ping', Math.round(bot.ws.ping)); 38 | embed.setColor('RANDOM'); 39 | msg.channel.send(embed); 40 | break; 41 | 42 | case 'help': 43 | embed = new MessageEmbed(); 44 | embed.addField('Commands', `${prefix}party\n${prefix}ffa\n${prefix}exp\n${prefix}agar\n${prefix}invite\n${prefix}ping`); 45 | embed.setColor('RANDOM'); 46 | msg.channel.send(embed); 47 | break; 48 | 49 | case 'invite': 50 | embed = new MessageEmbed(); 51 | embed.setColor('RANDOM'); 52 | embed.setTitle('Bot Invite Link'); 53 | embed.setURL(`https://discordapp.com/oauth2/authorize?client_id=${bot.user.id}&scope=bot&permissions=7232`); 54 | msg.channel.send(embed); 55 | break; 56 | 57 | case 'agar': 58 | let latestID = await request('https://webbouncer-live-v8-0.agario.miniclippt.com/getLatestID'); 59 | let webBouncer = await request('https://webbouncer-live-v8-0.agario.miniclippt.com/info'); 60 | let xclientkey = await request('https://agar.io/mc/agario.js'); 61 | let versionString = xclientkey.match(/(?<=versionString=")[^"]+/)[0]; 62 | const { groups: { protoVersion } } = /proto-version.+?"(?\d+.+?)"/gm.exec(xclientkey); 63 | let versionInt = parseInt(versionString.split('.')[0]) * 10000 + parseInt(versionString.split('.')[1]) * 100 + parseInt(versionString.split('.')[2]); 64 | let init = new Uint8Array(new Uint32Array([versionInt]).buffer); 65 | let core = await request('https://agar.io/agario.core.js'); 66 | let protocolVersion = core.match(/d;..\(.,(\d+)\);/)[1]; 67 | let agar = JSON.parse(webBouncer); 68 | embed = new MessageEmbed(); 69 | embed.setColor('RANDOM'); 70 | embed.addField('Agar.io PC Servers', `Servers: ${agar.totals.numServers}\n Online: ${agar.totals.numEnabledServers}\nIdle: ${agar.totals.numServers - agar.totals.numEnabledServers}`); 71 | embed.addField('Players', `SG-Singapore: ${agar.regions['SG-Singapore'].numPlayers}\nUS-Atlanta: ${agar.regions['US-Atlanta'].numPlayers} 72 | EU-London: ${agar.regions['EU-London'].numPlayers}\nCN-China: ${agar.regions['CN-China'].numPlayers}\nBR-Brazil: ${agar.regions['BR-Brazil'].numPlayers} 73 | TK-Turkey: ${agar.regions['TK-Turkey'].numPlayers}\nRU-Russia: ${agar.regions['RU-Russia'].numPlayers}\nJP-Tokyo: ${agar.regions['JP-Tokyo'].numPlayers} 74 | Total: ${agar.totals.numPlayers}`); 75 | embed.addField('Info', `Proto Version: ${protoVersion}\nProtocol Key: ${versionInt}\nProtocol Version: ${protocolVersion}\n[ ${[255, init]} ] 76 | LatestID: ${latestID}\n[Config](https://configs-web.agario.miniclippt.com/live/v15/${latestID}/GameConfiguration.json)`); 77 | msg.channel.send(embed); 78 | break; 79 | 80 | case 'ffa': 81 | case 'exp': 82 | if (!args[1] || !args[1].toUpperCase().match(/EU|RU|TK|CN|US|JP|BR|SG/)) { 83 | embed = new MessageEmbed(); 84 | embed.setColor('RANDOM'); 85 | embed.addField('Agar.io Regions', 'CN (China)\nTK (Turkey)\nEU (London)\nUS (Atlanta)\nBR (Brazil)\nJP (Tokyo)\nRU (Russia)\nSG (Singapore)'); 86 | embed.addField('Usage', `${prefix}gamemode region`); 87 | return msg.channel.send(embed); 88 | } 89 | 90 | embed = new MessageEmbed(); 91 | embed.setColor('RANDOM'); 92 | 93 | requestV4('findServer', generateBytes(args[1], args[0] == 'ffa' ? ':ffa' : ':experimental'), body => { 94 | let ip = `${body.endpoints.https.includes('ip') ? 'ws://' + body.endpoints.https : 'wss://' + body.endpoints.https}`; 95 | embed.addField('Server info', `Link: https://agar.io/?sip=${body.endpoints.https}\nRegion: ${generateBytes(args[1], 'region')}\nIP: ${ip}`); 96 | msg.channel.send(embed); 97 | }); 98 | 99 | break; 100 | 101 | case 'party': 102 | if (!args[1] || args[1].length == 2 && !args[1].toUpperCase().match(/EU|RU|TK|CN|US|JP|BR|SG/)) { 103 | embed = new MessageEmbed(); 104 | embed.setColor('RANDOM'); 105 | embed.addField('Agar.io Regions', 'CN (China)\nTK (Turkey)\nEU (London)\nUS (Atlanta)\nBR (Brazil)\nJP (Tokyo)\nRU (Russia)\nSG (Singapore)'); 106 | embed.addField('Creating party', `${prefix}party region`); 107 | embed.addField('Checking party', `${prefix}party code`); 108 | return msg.channel.send(embed); 109 | } 110 | 111 | embed = new MessageEmbed(); 112 | embed.setColor('RANDOM'); 113 | 114 | 115 | if (args[1].length == 2) { 116 | 117 | requestV4('findServer', generateBytes(args[1], ':party'), body => { 118 | if (body.status !== 'no_servers') { 119 | var ip = `${body.endpoints.https.includes('ip') ? 'ws://' + body.endpoints.https : 'wss://' + body.endpoints.https}?party_id=${body.token}`; 120 | embed.addField('Party info', `Link: https://agar.io/#${body.token}\nRegion: ${generateBytes(args[1], 'region')}\nCode: ${body.token}\nIP: ${ip}`); 121 | msg.channel.send(embed); 122 | } 123 | else { 124 | requestV4('createToken', generateBytes(args[1], ':party'), body => { 125 | let partyToken = body.token; 126 | requestV4('getToken', generateBytes(args[1], false, partyToken), body => { 127 | ip = `${body.endpoints.https.includes('ip') ? 'ws://' + body.endpoints.https : 'wss://' + body.endpoints.https}?party_id=${body.token}`; 128 | embed.addField('Party info', `Link: https://agar.io/#${partyToken}\nRegion: ${generateBytes(args[1], 'region')}\nCode: ${partyToken}\nIP: ${ip}`); 129 | msg.channel.send(embed); 130 | }); 131 | }); 132 | } 133 | }); 134 | 135 | } 136 | else { 137 | 138 | if (args[1].startsWith('#')) args[1] = args[1].split('#')[1]; 139 | requestV4('getToken', generateBytes('eu', false, args[1].toUpperCase()), body => { 140 | 141 | if (!body.status) { 142 | embed.setTitle('invalid party code'); 143 | return msg.channel.send(embed); 144 | } 145 | 146 | let ip = `${body.endpoints.https.includes('ip') ? 'ws://' + body.endpoints.https : 'wss://' + body.endpoints.https}?party_id=${args[1].toUpperCase()}`; 147 | 148 | new Bot(ip, (leaderboard, friends, minimap) => { 149 | let leaderboardx = '```' + leaderboard.slice(0, 10).join('') + '```'; 150 | let totalMass = 0; 151 | minimap.forEach(m => { 152 | totalMass += m.mass; 153 | }); 154 | totalMass = 1e3 > totalMass ? totalMass : Math.round(totalMass / 100) / 10 + 'k'; 155 | embed.addField('Party info', `\nLEADERBOARD\n\n${leaderboardx}\nIP: ${ip}\nTotal mass: ${totalMass}\nPlayers: ${leaderboard.length}\nFriends: ${friends}\nStatus: ${body.status}`); 156 | msg.channel.send(embed); 157 | }); 158 | 159 | }); 160 | } 161 | break; 162 | 163 | } 164 | }); 165 | 166 | function requestV4(action, token, callback) { 167 | request({ 168 | url: `https://webbouncer-live-v8-0.agario.miniclippt.com/v4/${action}`, 169 | method: 'POST', 170 | headers: { 171 | 'Content-Type': 'application/json', 172 | 'x-client-version': global.versionInt, 173 | 'x-support-proto-version': global.protoVersion 174 | }, 175 | body: Buffer.from(token) 176 | }).then(body => { 177 | body = JSON.parse(body); 178 | callback(body); 179 | }).catch(e => { 180 | callback(e); 181 | }); 182 | } 183 | 184 | function generateBytes(args, mode, token) { 185 | 186 | const regions = { 187 | sg: 'SG-Singapore', 188 | us: 'US-Atlanta', 189 | eu: 'EU-London', 190 | tk: 'TK-Turkey', 191 | br: 'BR-Brazil', 192 | ru: 'RU-Russia', 193 | jp: 'JP-Tokyo', 194 | cn: 'CN-China', 195 | }; 196 | 197 | if (mode == 'region') return regions[args]; 198 | 199 | const getOwnPropertyNames = function (data) { 200 | output.push(data.length); 201 | for (let value = 0; value < data.length; value++) { 202 | output.push(data.charCodeAt(value)); 203 | } 204 | }; 205 | 206 | if (token) { 207 | var output = [10, 4 + regions[args].length + 4, 10]; 208 | getOwnPropertyNames(regions[args]); 209 | output.push(18); 210 | getOwnPropertyNames(':ffa'); 211 | output.push(26, 8, 10); 212 | getOwnPropertyNames(token); 213 | return new Uint8Array(output); 214 | } 215 | 216 | output = [10, 4 + regions[args].length + mode.length, 10]; 217 | getOwnPropertyNames(regions[args]); 218 | output.push(18); 219 | getOwnPropertyNames(mode); 220 | return new Uint8Array(output); 221 | } 222 | 223 | function update() { 224 | setInterval(async () => { 225 | let xclientkey = await request('https://agar.io/mc/agario.js'); 226 | let versionString = xclientkey.match(/(?<=versionString=")[^"]+/)[0]; 227 | let versionInt = parseInt(versionString.split('.')[0]) * 10000 + parseInt(versionString.split('.')[1]) * 100 + parseInt(versionString.split('.')[2]); 228 | const { groups: { protoVersion } } = /proto-version.+?"(?\d+.+?)"/gm.exec(xclientkey); 229 | let core = await request('https://agar.io/agario.core.js'); 230 | let protocolVersion = core.match(/d;..\(.,(\d+)\);/)[1]; 231 | global.protocolVersion = protocolVersion; 232 | global.protoVersion = protoVersion; 233 | global.versionInt = versionInt; 234 | }, 3.6e+6); 235 | } 236 | 237 | class Bot { 238 | constructor(server, callback) { 239 | 240 | this.encryptionKey = null; 241 | this.decryptionKey = null; 242 | this.callback = callback; 243 | this.friendsCounter = 0; 244 | this.leaderboard = []; 245 | this.server = server; 246 | this.connect(); 247 | } 248 | 249 | connect() { 250 | this.ws = new WebSocket(this.server); 251 | this.ws.binaryType = 'nodebuffer'; 252 | 253 | this.ws.onopen = () => { 254 | let buf = new Buffer.alloc(5); 255 | buf.writeUInt8(254, 0); 256 | buf.writeUInt32LE(global.protocolVersion, 1); 257 | this.ws.send(buf); 258 | 259 | buf = new Buffer.alloc(5); 260 | buf.writeUInt8(255, 0); 261 | buf.writeUInt32LE(global.versionInt, 1); 262 | this.ws.send(buf); 263 | }; 264 | 265 | this.ws.onmessage = msg => { 266 | msg = new Buffer.from(msg.data); 267 | let offset = 0; 268 | 269 | if (this.decryptionKey) msg = this.xor(msg, this.decryptionKey); 270 | 271 | switch (msg.readUInt8(offset++)) { 272 | case 241: 273 | this.decryptionKey = global.versionInt ^ msg.readInt32LE(offset); 274 | msg = Array.from(msg).splice(5, 11); 275 | 276 | this.encryptionKey = murmur2(this.ws.url, new Uint8Array(msg), 255); 277 | break; 278 | 279 | case 54: 280 | if (!this.minimap) return; 281 | for (let i = 0; offset < msg.byteLength;) { 282 | this.sizrex = false; 283 | let flag = msg.readUInt8(offset++); 284 | if (flag & 2) { 285 | let x, d = ''; 286 | while ((x = msg.readUInt8(offset++)) != 0) { 287 | d += String.fromCharCode(x); 288 | } 289 | if (!d || d == '' || d.toLowerCase().match(/agarbot|morebots/)) this.sizrex = true; 290 | if (i >= 11) this.leaderboard.push(`${i + 1}. ${this.sizrex ? 'OP-Bots.com' : decodeURIComponent(escape(d))}\n`); 291 | else this.leaderboard.push(`${i + 1}. ${this.sizrex ? 'OP-Bots.com' : decodeURIComponent(escape(d))} (${this.shortMass(this.minimap[i++].mass)})\n`); 292 | } 293 | if (flag & 4) offset += 4; 294 | if (flag & 16) this.friendsCounter++; 295 | } 296 | this.callback(this.leaderboard, this.friendsCounter, this.minimap); 297 | this.ws.close(); 298 | break; 299 | 300 | case 69: 301 | let x = 0; 302 | let d = msg.readUInt16LE(offset); 303 | for (offset += 2, this.minimap = [], x = 0; x < d; x++) { 304 | let x = msg.readInt32LE(offset); 305 | offset += 4; 306 | let y = msg.readInt32LE(offset); 307 | offset += 4; 308 | let mass = msg.readInt32LE(offset); 309 | offset += 5; 310 | let size = ~~Math.sqrt(100 * mass); 311 | this.minimap.push({ 312 | x: x, 313 | y: y, 314 | size: size, 315 | mass: mass, 316 | }); 317 | } 318 | this.minimap.sort((a, b) => { return b.mass - a.mass; }); 319 | break; 320 | } 321 | }; 322 | } 323 | 324 | shortMass(e) { 325 | return 1e3 > e ? e : Math.round(e / 100) / 10 + 'k'; 326 | } 327 | 328 | xor(buf, xorKey) { 329 | const newBuf = new Buffer.alloc(buf.byteLength); 330 | for (let i = 0; i < buf.byteLength; i++) newBuf.writeUInt8(buf.readUInt8(i) ^ xorKey >>> i % 4 * 8 & 255, i); 331 | return newBuf; 332 | } 333 | } 334 | 335 | bot.on('error', err => { 336 | if (err.msg === 'ECONNRESET' || err.msg === 'ERROR' || err.statusCode === 520 || !err.msg) return; 337 | console.log(err); 338 | }); 339 | 340 | bot.login(config.token); 341 | --------------------------------------------------------------------------------