├── vars ├── globals.js ├── settings.js ├── enums.js └── opcodes.js ├── .gitignore ├── logic ├── client │ ├── world │ │ └── World.js │ ├── teleport │ │ └── Teleport.js │ ├── ping │ │ └── Ping.js │ ├── packet │ │ └── ClientPacketManager.js │ ├── spawns │ │ ├── GroupSpawn.js │ │ ├── SpawnManager.js │ │ └── SpawnParser.js │ ├── character │ │ ├── CharList.js │ │ └── CharData.js │ ├── items │ │ └── InventoryParser.js │ └── login │ │ └── Login.js └── server │ ├── packet │ └── ServerPacketManager.js │ ├── ServerLogic.js │ └── ServerSpawns.js ├── package.json ├── functions.js ├── app.js ├── helper.js ├── blowfish ├── helper.js └── Blowfish.js ├── README.md ├── packet ├── PacketReader.js └── PacketWriter.js ├── gamedata └── GameData.js ├── connections ├── Client.js └── Server.js ├── Bot.js └── security └── Security.js /vars/globals.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | clientState: { 3 | id: 10, 4 | name: 'Offline', 5 | }, 6 | sessionId: 0, 7 | loginMaxTry: 0, 8 | loginCurTry: 0, 9 | 10 | firstSpawnAccepted: false, 11 | }; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | gamedata/data 3 | !gamedata/data/chardataSample.txt 4 | !gamedata/data/itemdataSample.txt 5 | !gamedata/data/skilldataSample.txt 6 | !gamedata/data/teleportbuildingSample.txt 7 | log 8 | npm-debug.log -------------------------------------------------------------------------------- /logic/client/world/World.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | var PacketWriter = require('../../../packet/PacketWriter'); 3 | var functions = require('../../../functions'); 4 | 5 | module.exports = { 6 | World: World 7 | }; 8 | 9 | var $World = World.prototype; 10 | $World.weather = World$weather; 11 | 12 | function World(bot) { 13 | this._bot = bot; 14 | 15 | this.weatherPacket = null; 16 | } 17 | 18 | function World$weather(packet) { 19 | this.weatherPacket = packet; 20 | } -------------------------------------------------------------------------------- /vars/settings.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | host: '127.0.0.1', 3 | port: 15779, 4 | locale: 23, 5 | version: 188, 6 | 7 | serverId: null, 8 | username: null, 9 | password: null, 10 | charName: null, 11 | 12 | autologin: false, 13 | 14 | server: { 15 | host: '127.0.0.1', 16 | }, 17 | 18 | // do not edit these unless you know what you do 19 | system: { 20 | connectToAgentServer: true, 21 | requestCharList: true, 22 | acceptTeleportRequest: true, 23 | }, 24 | }; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "silkroad-bot", 3 | "version": "1.0.0", 4 | "description": "Prototype of the client based bot of the game Silkroad Online. It works as a proxy server between game client and a game server.", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Simonas Valencius ", 10 | "license": "ISC", 11 | "dependencies": { 12 | "hexdump-nodejs": "^0.1.0", 13 | "hexy": "^0.2.9", 14 | "long": "^3.2.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /logic/client/teleport/Teleport.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | var EventEmitter = require('events').EventEmitter; 3 | var PacketWriter = require('../../../packet/PacketWriter'); 4 | 5 | module.exports = { 6 | Teleport: Teleport 7 | }; 8 | 9 | util.inherits(Teleport, EventEmitter); 10 | 11 | var $Teleport = Teleport.prototype; 12 | $Teleport.teleportRequest = Teleport$teleportRequest; 13 | 14 | function Teleport(bot) { 15 | EventEmitter.call(this); 16 | 17 | this._bot = bot; 18 | } 19 | 20 | function Teleport$teleportRequest(packet) { 21 | if(this._bot.settings.system.acceptTeleportRequest){ 22 | this._bot.client.send(this._bot.opcodes.CLIENT.TELEPORT_ACCEPT, new PacketWriter(), false); 23 | } 24 | this.emit('teleportRequest'); 25 | } 26 | 27 | -------------------------------------------------------------------------------- /vars/enums.js: -------------------------------------------------------------------------------- 1 | module.exports.clientState = { 2 | OFFLINE: { 3 | id: 10, 4 | name: 'Offline', 5 | }, 6 | IDENTIFIED: { 7 | id: 20, 8 | name: 'Identified', 9 | }, 10 | WAITING_LOGIN: { 11 | id: 30, 12 | name: 'Waiting login', 13 | }, 14 | WAITING_CAPTCHA: { 15 | id: 40, 16 | name: 'Waiting captcha', 17 | }, 18 | WAITING_CHAR_SELECTION: { 19 | id: 50, 20 | name: 'Waiting character selection', 21 | }, 22 | LOADING_GAME_WORLD: { 23 | id: 51, 24 | name: 'Loading into game world', 25 | }, 26 | IN_GAME: { 27 | id: 60, 28 | name: 'In game world', 29 | }, 30 | TELEPORTING: { 31 | id: 70, 32 | name: 'Teleporting', 33 | } 34 | }; 35 | 36 | module.exports.serverType = { 37 | GATEWAY_SERVER: "GatewayServer", 38 | AGENT_SERVER: "AgentServer", 39 | }; -------------------------------------------------------------------------------- /functions.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | calculateX: calculateX, 3 | calculateY: calculateY, 4 | } 5 | 6 | function calculateX(xSector, xOffset){ 7 | return parseInt((xSector - 135) * 192 + xOffset / 10); 8 | } 9 | 10 | function calculateY(ySector, yOffset){ 11 | return parseInt((ySector - 92) * 192 + yOffset / 10); 12 | } 13 | 14 | if (typeof String.prototype.startsWith != 'function') { 15 | String.prototype.startsWith = function (str){ 16 | return this.slice(0, str.length) == str; 17 | }; 18 | } 19 | 20 | if (typeof String.prototype.endsWith != 'function') { 21 | String.prototype.endsWith = function (str){ 22 | return this.slice(-str.length) == str; 23 | }; 24 | } 25 | 26 | if (typeof String.prototype.contains != 'function') { 27 | String.prototype.contains = function (str){ 28 | return this.indexOf(str) > -1; 29 | }; 30 | } -------------------------------------------------------------------------------- /logic/client/ping/Ping.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | var EventEmitter = require('events').EventEmitter; 3 | var PacketWriter = require('../../../packet/PacketWriter'); 4 | 5 | module.exports = { 6 | Ping: Ping 7 | }; 8 | 9 | var $Ping = Ping.prototype; 10 | $Ping.start = Ping$start; 11 | $Ping.stop = Ping$stop; 12 | $Ping._ping = Ping$_ping; 13 | 14 | function Ping(bot) { 15 | this._bot = bot; 16 | this.timer = null; 17 | this.delay = 7000; 18 | } 19 | 20 | function Ping$start() { 21 | var self = this; 22 | this.timer = setInterval(function() { 23 | self._ping(); 24 | }, this.delay); 25 | } 26 | 27 | function Ping$stop() { 28 | clearInterval(this.timer); 29 | } 30 | 31 | function Ping$_ping() { 32 | if(this._bot.globals.clientState != this._bot.enums.clientState.OFFLINE) { 33 | this._bot.client.send(this._bot.opcodes.CLIENT.PING, new PacketWriter()); 34 | } 35 | } -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | var Bot = require('./Bot'); 2 | 3 | var bot = Bot.create({ host: '127.0.0.1', port: 15809, locale: 22, version: 206 }); // Configure server settings 4 | 5 | bot.start(); 6 | 7 | bot.on('serverListening', function(port) { 8 | console.log('Bot is waiting game client connection on port: ', port); 9 | }); 10 | 11 | bot.on('clientError', function(error){ 12 | console.log('Client error', error); 13 | }); 14 | 15 | bot.on('clientClose', function(hadError){ 16 | console.log('Client close', hadError); 17 | }); 18 | 19 | bot.on('serverList', function(serverList){ 20 | console.log(serverList); 21 | bot.sendLogin('username', 'password', 1); // Enter login details 22 | }); 23 | 24 | bot.on('loginError', function(error){ 25 | console.log(error); 26 | }); 27 | 28 | bot.on('loginResponse', function(data){ 29 | console.log(data); 30 | }); 31 | 32 | bot.on('gameLoginResponse', function(data){ 33 | console.log(data); 34 | }); 35 | 36 | bot.on('charList', function(charList){ 37 | console.log(charList); 38 | bot.selectCharacter('TheVeryCharacter'); // Choose your character 39 | }); 40 | 41 | bot.on('charListError', function(error){ 42 | console.log(error); 43 | }); 44 | 45 | bot.on('characterSelected', function(error){ 46 | console.log('Character selected!'); 47 | }); 48 | 49 | bot.on('charData', function(character){ 50 | console.log('Successfully got chardata!'); 51 | }); -------------------------------------------------------------------------------- /helper.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | toUInt32: toUInt32, 3 | toUInt32_: toUInt32_, 4 | MAKELONGLONG_: MAKELONGLONG_, 5 | MAKELONG_: MAKELONG_, 6 | MAKEWORD_: MAKEWORD_, 7 | LOWORD_: LOWORD_, 8 | HIWORD_: HIWORD_, 9 | LOBYTE_: LOBYTE_, 10 | HIBYTE_: HIBYTE_ 11 | }; 12 | 13 | function toUInt32(sval) { 14 | var buffer = new Buffer(4); 15 | buffer.writeInt32LE(sval, 0); 16 | var usigned = buffer.readUInt32LE(0); 17 | return usigned; 18 | } 19 | 20 | function toUInt32_(sval) { 21 | var buffer = new Buffer(5); 22 | buffer.writeUInt32LE(sval, 0); 23 | var usigned = buffer.readUInt32LE(0); 24 | return usigned; 25 | } 26 | 27 | function MAKELONGLONG_(a, b) { 28 | var longlong = ((b << 32) | a); 29 | var buffer = new Buffer(8); 30 | buffer.writeInt64LE(longlong, 0); 31 | longlong = buffer.readUInt64LE(0); 32 | return longlong; 33 | } 34 | 35 | function MAKELONG_(a, b) { 36 | var long = ((b << 16) | a); 37 | var buffer = new Buffer(4); 38 | buffer.writeInt32LE(long, 0); 39 | long = buffer.readUInt32LE(0); 40 | return long; 41 | } 42 | 43 | function MAKEWORD_(a, b) { 44 | var word = ((b << 8) | a); 45 | var buffer = new Buffer(2); 46 | buffer.writeInt16LE(word, 0); 47 | word = buffer.readUInt16LE(0); 48 | return word; 49 | } 50 | 51 | function LOWORD_(a) { 52 | a = a & 0xffff; 53 | var buffer = new Buffer(2); 54 | buffer.writeUInt16LE(a, 0); 55 | a = buffer.readUInt16LE(0); 56 | return a; 57 | } 58 | 59 | function HIWORD_(a) { 60 | a = (a >>> 16) & 0xffff; 61 | return a; 62 | } 63 | 64 | function LOBYTE_(a) { 65 | a = a & 0xff; 66 | return a; 67 | } 68 | 69 | function HIBYTE_(a) { 70 | a = ((a >>> 8) & 0xff); 71 | return a; 72 | } -------------------------------------------------------------------------------- /blowfish/helper.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | toUInt32: toUInt32, 3 | toUInt32_: toUInt32_, 4 | MAKELONGLONG_: MAKELONGLONG_, 5 | MAKELONG_: MAKELONG_, 6 | MAKEWORD_: MAKEWORD_, 7 | LOWORD_: LOWORD_, 8 | HIWORD_: HIWORD_, 9 | LOBYTE_: LOBYTE_, 10 | HIBYTE_: HIBYTE_ 11 | }; 12 | 13 | function toUInt32(sval) { 14 | var buffer = new Buffer(4); 15 | buffer.writeInt32LE(sval, 0); 16 | var usigned = buffer.readUInt32LE(0); 17 | return usigned; 18 | } 19 | 20 | function toUInt32_(sval) { 21 | var buffer = new Buffer(5); 22 | buffer.writeUInt32LE(sval, 0); 23 | var usigned = buffer.readUInt32LE(0); 24 | return usigned; 25 | } 26 | 27 | function MAKELONGLONG_(a, b) { 28 | var longlong = ((b << 32) | a); 29 | var buffer = new Buffer(8); 30 | buffer.writeInt64LE(longlong, 0); 31 | longlong = buffer.readUInt64LE(0); 32 | return longlong; 33 | } 34 | 35 | function MAKELONG_(a, b) { 36 | var long = ((b << 16) | a); 37 | var buffer = new Buffer(4); 38 | buffer.writeInt32LE(long, 0); 39 | long = buffer.readUInt32LE(0); 40 | return long; 41 | } 42 | 43 | function MAKEWORD_(a, b) { 44 | var word = ((b << 8) | a); 45 | var buffer = new Buffer(2); 46 | buffer.writeInt16LE(word, 0); 47 | word = buffer.readUInt16LE(0); 48 | return word; 49 | } 50 | 51 | function LOWORD_(a) { 52 | a = a & 0xffff; 53 | var buffer = new Buffer(2); 54 | buffer.writeUInt16LE(a, 0); 55 | a = buffer.readUInt16LE(0); 56 | return a; 57 | } 58 | 59 | function HIWORD_(a) { 60 | a = (a >>> 16) & 0xffff; 61 | return a; 62 | } 63 | 64 | function LOBYTE_(a) { 65 | a = a & 0xff; 66 | return a; 67 | } 68 | 69 | function HIBYTE_(a) { 70 | a = ((a >>> 8) & 0xff); 71 | return a; 72 | } -------------------------------------------------------------------------------- /logic/client/packet/ClientPacketManager.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | var PacketWriter = require('../../../packet/PacketWriter'); 3 | var functions = require('../../../functions'); 4 | 5 | module.exports = { 6 | ClientPacketManager: ClientPacketManager 7 | }; 8 | 9 | var $ClientPacketManager = ClientPacketManager.prototype; 10 | $ClientPacketManager.forwardPacket = ClientPacketManager$forwardPacket; 11 | 12 | function ClientPacketManager(bot) { 13 | this._bot = bot; 14 | 15 | this._packetBlackList = []; 16 | 17 | this._packetBlackList.push(this._bot.opcodes.CLIENT.HANDSHAKE); 18 | this._packetBlackList.push(this._bot.opcodes.CLIENT.HANDSHAKE_OK); 19 | this._packetBlackList.push(this._bot.opcodes.CLIENT.AGENT_SERVER); 20 | this._packetBlackList.push(this._bot.opcodes.CLIENT.PING); 21 | this._packetBlackList.push(this._bot.opcodes.CLIENT.GAME_LOGIN); 22 | this._packetBlackList.push(this._bot.opcodes.CLIENT.REQUEST_SERVER_LIST); 23 | this._packetBlackList.push(this._bot.opcodes.CLIENT.LOCATION_REQUEST); 24 | this._packetBlackList.push(this._bot.opcodes.CLIENT.CHARACTER_LIST); 25 | this._packetBlackList.push(this._bot.opcodes.CLIENT.CHARACTER_SELECT); 26 | this._packetBlackList.push(this._bot.opcodes.CLIENT.CONFIRM_SPAWN); 27 | this._packetBlackList.push(this._bot.opcodes.CLIENT.WEATHER_REQUEST); 28 | } 29 | 30 | function ClientPacketManager$forwardPacket(packet, client) { 31 | if(packet && this._bot.globals.clientState != this._bot.enums.clientState.OFFLINE && this._packetBlackList.indexOf(packet.opcode) == -1 && client.state == this._bot.enums.clientState.IN_GAME) { 32 | var tmpBuffer, p; 33 | //Set pointer to beginning 34 | packet.pointer = 6; 35 | tmpBuffer = packet.readByteArray(packet.size); 36 | p = new PacketWriter(tmpBuffer); 37 | this._bot.client.send(packet.opcode, p, packet.encrypted); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /logic/client/spawns/GroupSpawn.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | var PacketWriter = require('../../../packet/PacketWriter'); 3 | var PacketReader = require('../../../packet/PacketReader'); 4 | var functions = require('../../../functions'); 5 | 6 | module.exports = { 7 | GroupSpawn: GroupSpawn 8 | }; 9 | 10 | var $GroupSpawn = GroupSpawn.prototype; 11 | $GroupSpawn.groupSpawnBegin = GroupSpawn$groupSpawnBegin; 12 | $GroupSpawn.groupSpawnData = GroupSpawn$groupSpawnData; 13 | $GroupSpawn.groupSpawnEnd = GroupSpawn$groupSpawnEnd; 14 | 15 | function GroupSpawn(bot) { 16 | this._bot = bot; 17 | 18 | this.groupSpawnDataPackets = []; 19 | this.action = 0; 20 | this.count = 0; 21 | } 22 | 23 | function GroupSpawn$groupSpawnBegin(packet) { 24 | this.action = packet.readByte(); 25 | this.count = packet.readWord(); 26 | } 27 | 28 | function GroupSpawn$groupSpawnData(packet) { 29 | this.groupSpawnDataPackets.push(packet); 30 | /* 31 | if(!this.groupSpawnPacketData) { 32 | this.groupSpawnPacketData = packet; 33 | } else { 34 | this.groupSpawnPacketData.buffer = Buffer.concat([this.groupSpawnPacketData.buffer, packet.buffer]); 35 | } 36 | */ 37 | } 38 | 39 | function GroupSpawn$groupSpawnEnd(packet) { 40 | var integralBuffer, integralPacket; 41 | integralBuffer = new Buffer(0); 42 | 43 | for(var i = 0; i < this.groupSpawnDataPackets.length; i++) { 44 | integralBuffer = Buffer.concat([integralBuffer, this.groupSpawnDataPackets[i].readByteArray(this.groupSpawnDataPackets[i].buffer.length - this.groupSpawnDataPackets[i].pointer)]); 45 | } 46 | integralPacket = new PacketReader(integralBuffer); 47 | integralPacket.pointer = 0; 48 | 49 | this._bot.spawnManager.parseGroupSpawn(integralPacket, this.action, this.count); 50 | 51 | //flush groupSpawnDataPackets for the next incoming group spawn data 52 | this.groupSpawnDataPackets.splice(0, this.groupSpawnDataPackets.length); 53 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | This was my project written some years ago. Main idea was to write silkroad client in Javascript which is able to bypass security, login and spawn character into game world and repeatedly send ping packet to game server to keep alive connection. Later I got great idea to open listening port and accept connections from original game client and forward it to orginal game server making this bot work as a proxy server. 3 | Since Silkroad Online started to lose its popularity and I got no interest into it anymore I decided to share this project to somebody who's still interested. 4 | 5 | ### Bot client 6 | I used Security API algorithm written by PushEDX and rewrited it in Javascript. I worked with vSRO version but this project can be reconfigured to work with other versions of SRO. 7 | 8 | ### Bot server 9 | The greatest idea of this project is the server who's accepts connections from original game client and forwards packets to original game server. [Original game client -> Bot server] and [Bot client -> Original game server] have seperate encryptions so it means that all packets going trough are decoded and can be manipulated. 10 | Bot server accepts multiple connections as well so you can run multiple original game clients and get same view in each of them. I did that because I had further vision to build different account types allowing users to let use their game characters to another users keeping game account passwords secret. 11 | 12 | As well you can original game client anytime you can. Bot keeps all required packets in memory and serves them to orginal game client when it starts connection. 13 | This functionality is still crashing near crowd of people (towns, pvp arenas, etc) due to lack of fully reversed packet structures. 14 | 15 | ### About gateway and agent servers 16 | Basic principle of original game client is that first it connect to gateway server to deal with the login and get IP of agent server. Later shuts gateway connection down and connects to agent server with temporary ID the gateway server gave. 17 | I discovered that original game client can actually be launched without any crash by serving directly agent server type. So if the bot client is already connected to original game server, we can serve agent server data without any login communication. Looks really nice when launching game client :) 18 | 19 | -------------------------------------------------------------------------------- /packet/PacketReader.js: -------------------------------------------------------------------------------- 1 | var $PacketReader = PacketReader.prototype; 2 | $PacketReader.readByte = PacketReader$readByte; 3 | $PacketReader.readWord = PacketReader$readWord; 4 | $PacketReader.readDWord = PacketReader$readDWord; 5 | $PacketReader.readQWord = PacketReader$readQWord; 6 | $PacketReader.readString = PacketReader$readString; 7 | $PacketReader.readFloat = PacketReader$readFloat; 8 | $PacketReader.readBool = PacketReader$readBool; 9 | $PacketReader.readByteArray = PacketReader$readByteArray; 10 | $PacketReader.rawBuffer = PacketReader$rawBuffer; 11 | 12 | module.exports = PacketReader; 13 | 14 | function PacketReader(data) { 15 | var buffer; 16 | 17 | buffer = this.buffer = data; 18 | this.size = buffer.readUInt16LE(0); 19 | this.opcode = buffer.readUInt16LE(2); 20 | this.encrypted = false; 21 | this.securityCount = buffer.readUInt8(4); 22 | this.securityCRC = buffer.readUInt8(5); 23 | this.pointer = 6; 24 | } 25 | 26 | function PacketReader$readByte() { 27 | var tmp = this.buffer.readUInt8(this.pointer); 28 | this.pointer++; 29 | return tmp; 30 | } 31 | 32 | function PacketReader$readWord() { 33 | var tmp = this.buffer.readUInt16LE(this.pointer); 34 | this.pointer += 2; 35 | return tmp; 36 | } 37 | 38 | function PacketReader$readDWord() { 39 | var tmp = this.buffer.readUInt32LE(this.pointer); 40 | this.pointer += 4; 41 | return tmp; 42 | } 43 | 44 | function PacketReader$readQWord() { 45 | var tmp = this.buffer.readDoubleLE(this.pointer); 46 | this.pointer += 8; 47 | return tmp; 48 | } 49 | 50 | function PacketReader$readString(ascii) { 51 | if (ascii) { 52 | var len = this.readWord(); 53 | var str = this.buffer.toString('utf8', this.pointer, this.pointer + len); 54 | this.pointer += len; 55 | return str; 56 | } 57 | } 58 | 59 | function PacketReader$readFloat() { 60 | var tmp = this.buffer.readFloatLE(this.pointer); 61 | this.pointer += 4; 62 | return tmp; 63 | } 64 | 65 | function PacketReader$readBool() { 66 | var tmp = this.buffer.readUInt8(this.pointer); 67 | if (tmp == 1) { 68 | return true; 69 | } 70 | else { 71 | return false; 72 | } 73 | } 74 | 75 | function PacketReader$readByteArray(size) { 76 | return this.buffer.slice(this.pointer, this.pointer + size); 77 | } 78 | 79 | function PacketReader$rawBuffer() { 80 | return this.buffer; 81 | } 82 | -------------------------------------------------------------------------------- /packet/PacketWriter.js: -------------------------------------------------------------------------------- 1 | var $PacketWriter = PacketWriter.prototype; 2 | $PacketWriter.writeByte = PacketWriter$writeByte; 3 | $PacketWriter.writeWord = PacketWriter$writeWord; 4 | $PacketWriter.writeDWord = PacketWriter$writeDWord; 5 | $PacketWriter.writeQWord = PacketWriter$writeQWord; 6 | $PacketWriter.writeString = PacketWriter$writeString; 7 | $PacketWriter.writeFloat = PacketWriter$writeFloat; 8 | $PacketWriter.setPointer = PacketWriter$setPointer; 9 | $PacketWriter.resetPointer = PacketWriter$resetPointer; 10 | $PacketWriter.getBytes = PacketWriter$getBytes; 11 | 12 | module.exports = PacketWriter; 13 | 14 | function PacketWriter(buffer) { 15 | this.buffer = new Buffer(4096); 16 | this.pointer = 0; 17 | this.size = 0; 18 | 19 | if (buffer) { 20 | buffer.copy(this.buffer); 21 | this.pointer = this.size = buffer.length; 22 | } 23 | } 24 | 25 | function PacketWriter$writeByte(b) { 26 | this.buffer.writeUInt8(b, this.pointer); 27 | if (this.pointer == this.size) { 28 | this.pointer += 1; 29 | this.size += 1; 30 | } else { 31 | this.pointer += 1; 32 | } 33 | } 34 | 35 | function PacketWriter$writeWord(w) { 36 | this.buffer.writeUInt16LE(w, this.pointer); 37 | if (this.pointer == this.size) { 38 | this.pointer += 2; 39 | this.size += 2; 40 | } else { 41 | this.pointer += 2; 42 | } 43 | } 44 | 45 | function PacketWriter$writeDWord(dw) { 46 | this.buffer.writeUInt32LE(dw, this.pointer); 47 | if (this.pointer == this.size) { 48 | this.pointer += 4; 49 | this.size += 4; 50 | } else { 51 | this.pointer += 4; 52 | } 53 | } 54 | 55 | function PacketWriter$writeQWord(qw) { 56 | this.buffer.writeDoubleLE(qw, this.pointer); 57 | if (this.pointer == this.size) { 58 | this.pointer += 8; 59 | this.size += 8; 60 | } else { 61 | this.pointer += 8; 62 | } 63 | } 64 | 65 | function PacketWriter$writeString(str) { 66 | var test = new String(str); 67 | var len = test.length; 68 | this.writeWord(len); 69 | this.buffer.write(str, this.pointer); 70 | if (this.pointer == this.size) { 71 | this.pointer += len; 72 | this.size += len; 73 | } else { 74 | this.pointer += len; 75 | } 76 | } 77 | 78 | function PacketWriter$writeFloat(f) { 79 | this.buffer.writeFloatLE(f, this.pointer); 80 | if (this.pointer == this.size) { 81 | this.pointer += 4; 82 | this.size += 4; 83 | } else { 84 | this.pointer += 4; 85 | } 86 | } 87 | 88 | function PacketWriter$setPointer(i) { 89 | this.pointer = i; 90 | } 91 | 92 | function PacketWriter$resetPointer() { 93 | this.pointer = this.size; 94 | } 95 | 96 | function PacketWriter$getBytes() { 97 | return this.buffer.slice(0, this.size); 98 | } 99 | -------------------------------------------------------------------------------- /vars/opcodes.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 3 | SERVER: { 4 | HANDSHAKE: 0x5000, 5 | BLOWFISH: 0x8000, 6 | AGENT_SERVER: 0x2001, 7 | PATCH_INFO: 0x600D, 8 | SERVER_LIST: 0xA101, 9 | CAPTCHA_REQUEST: 0x2322, 10 | LOGIN_REPLY: 0xA102, 11 | GAME_LOGIN_REPLY: 0xA103, 12 | LOCATION_REPLY: 0xA107, 13 | 14 | CHARACTER_LIST: 0xB007, 15 | CHARACTER_SELECT: 0xB001, 16 | 17 | CHARDATA_BEGIN: 0x34A5, 18 | CHARDATA_DATA: 0x3013, 19 | CHARDATA_END: 0x34A6, 20 | CHARDATA_ID: 0x3020, 21 | 22 | TELEPORT_REQUEST: 0x34B5, 23 | OBJECT_VISUAL: 0x305C, 24 | 25 | OBJECT_APPEARANCE: 0x30BF, 26 | 27 | CHARACTER_SPEED: 0x30D0, 28 | CHARACTER_INFO: 0x303D, 29 | CHARACTER_STUFF: 0x304E, 30 | OBJECT_EXPSP: 0x3056, 31 | OBJECT_HPMP: 0x3057, 32 | 33 | SINGLE_SPAWN: 0x3015, 34 | SINGLE_DESPAWN: 0x3016, 35 | GROUPSPAWN_BEGIN: 0x3017, 36 | GROUPSPAWN_DATA: 0x3019, 37 | GROUPSPAWN_END: 0x3018, 38 | 39 | INVENTORY_USE: 0xB04C, 40 | INVENTORY_MOVEMENT: 0xB034, 41 | DURABILITYCHANGE: 0x3052, 42 | ITEMFIXED: 0xB03E, 43 | 44 | OBJECT_MOVEMENT: 0xB021, 45 | OBJECT_STUCK: 0xB023, 46 | 47 | OBJECT_SELECT: 0xB045, 48 | OBJECT_ACTION: 0xB074, 49 | NPC_DESELECT: 0xB04B, 50 | NPC_SELECT: 0xB046, 51 | 52 | SKILL_CAST: 0xB070, 53 | SKILL_CASTED: 0xB071, 54 | 55 | BUFF_ADD: 0xB0BD, 56 | BUFF_DELL: 0xB072, 57 | 58 | STORAGE_GOLD: 0x3047, 59 | STORAGE_OK: 0x3048, 60 | STORAGE_ITEMS: 0x3049, 61 | 62 | PET_INFO: 0x30C8, 63 | PET_STATS: 0x30C9, 64 | 65 | WEATHER: 0x3809, 66 | }, 67 | 68 | CLIENT: { 69 | HANDSHAKE: 0x5000, 70 | HANDSHAKE_OK: 0x9000, 71 | AGENT_SERVER: 0x2001, 72 | PATCH_REQUEST: 0x6100, 73 | PING: 0x2002, 74 | GAME_LOGIN: 0x6103, 75 | LAUNCHER_NEWS: 0x6104, 76 | REQUEST_SERVER_LIST: 0x6101, 77 | LOGIN: 0x6102, 78 | CAPTCHA_REPLY: 0x6323, 79 | LOCATION_REQUEST: 0x6107, 80 | 81 | CHARACTER_LIST: 0x7007, 82 | CHARACTER_SELECT: 0x7001, 83 | 84 | CONFIRM_SPAWN: 0x3012, 85 | TELEPORT_ACCEPT: 0x34B6, 86 | TELEPORT_BEGIN: 0x705A, 87 | 88 | INVENTORY_USE: 0x704C, 89 | INVENTORY_MOVEMENT: 0x7034, 90 | 91 | OBJECT_MOVEMENT: 0x7021, 92 | 93 | OBJECT_SELECT: 0x7045, 94 | OBJECT_ACTION: 0x7074, 95 | NPC_SELECT: 0x7046, 96 | NPC_DESELECT: 0x704B, 97 | 98 | ZERK: 0x70A7, 99 | 100 | STORAGE_GETITEMS: 0x703C, 101 | DEAD_ACCEPT: 0x3053, 102 | 103 | WEATHER_REQUEST: 0x750E, 104 | 105 | LOGOUT_REQUEST: 0x7005, 106 | }, 107 | 108 | }; -------------------------------------------------------------------------------- /logic/server/packet/ServerPacketManager.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | var PacketWriter = require('../../../packet/PacketWriter'); 3 | var functions = require('../../../functions'); 4 | 5 | module.exports = { 6 | ServerPacketManager: ServerPacketManager 7 | }; 8 | 9 | var $ServerPacketManager = ServerPacketManager.prototype; 10 | $ServerPacketManager._sendPacket = ServerPacketManager$_sendPacket; 11 | //$ServerPacketManager._sendPacketAll = ServerPacketManager$_sendPacketAll; 12 | $ServerPacketManager.forwardPacket = ServerPacketManager$forwardPacket; 13 | $ServerPacketManager.forwardPacketAll = ServerPacketManager$forwardPacketAll; 14 | 15 | function ServerPacketManager(bot) { 16 | this._bot = bot; 17 | 18 | this._packetBlackList = []; 19 | 20 | this._packetBlackList.push(this._bot.opcodes.SERVER.HANDSHAKE); 21 | this._packetBlackList.push(this._bot.opcodes.SERVER.AGENT_SERVER); 22 | this._packetBlackList.push(this._bot.opcodes.SERVER.PATCH_INFO); 23 | this._packetBlackList.push(this._bot.opcodes.SERVER.PING); 24 | this._packetBlackList.push(this._bot.opcodes.SERVER.LOGIN_REPLY); 25 | this._packetBlackList.push(this._bot.opcodes.SERVER.CHARACTER_LIST); 26 | this._packetBlackList.push(this._bot.opcodes.SERVER.CHARACTER_SELECT); 27 | this._packetBlackList.push(this._bot.opcodes.SERVER.CHARDATA_BEGIN); 28 | this._packetBlackList.push(this._bot.opcodes.SERVER.CHARDATA_DATA); 29 | this._packetBlackList.push(this._bot.opcodes.SERVER.CHARDATA_END); 30 | this._packetBlackList.push(this._bot.opcodes.SERVER.CHARDATA_ID); 31 | this._packetBlackList.push(this._bot.opcodes.SERVER.WEATHER); 32 | //this._packetBlackList.push(this._bot.opcodes.SERVER.SINGLE_SPAWN); 33 | //this._packetBlackList.push(this._bot.opcodes.SERVER.SINGLE_DESPAWN); 34 | //this._packetBlackList.push(this._bot.opcodes.SERVER.GROUPSPAWN_BEGIN); 35 | //this._packetBlackList.push(this._bot.opcodes.SERVER.GROUPSPAWN_DATA); 36 | //this._packetBlackList.push(this._bot.opcodes.SERVER.GROUPSPAWN_END); 37 | } 38 | 39 | function ServerPacketManager$_sendPacket(client, packet) { 40 | var tmpBuffer, p; 41 | 42 | //Set pointer to beginning 43 | packet.pointer = 6; 44 | tmpBuffer = packet.readByteArray(packet.size); 45 | p = new PacketWriter(tmpBuffer); 46 | this._bot.server.send(client, packet.opcode, p, packet.encrypted); 47 | } 48 | 49 | // function ServerPacketManager$_sendPacketAll(packet) { 50 | // var tmpBuffer, p; 51 | 52 | // //Set pointer to beginning 53 | // packet.pointer = 6; 54 | // tmpBuffer = packet.readByteArray(packet.size); 55 | // p = new PacketWriter(tmpBuffer); 56 | // this._bot.server.sendAll(packet.opcode, p, packet.encrypted); 57 | // } 58 | 59 | function ServerPacketManager$forwardPacket(client, packet, bypassBlacklist) { 60 | console.log('[SERVER][S->C] '+ packet.opcode.toString('16')); 61 | bypassBlacklist = bypassBlacklist || false; 62 | if(packet) { 63 | if(this._packetBlackList.indexOf(packet.opcode) == -1 || bypassBlacklist) { 64 | this._sendPacket(client, packet); 65 | } 66 | } 67 | } 68 | 69 | function ServerPacketManager$forwardPacketAll(packet, bypassBlacklist) { 70 | console.log('[SERVER][ALL][S->C] '+ packet.opcode.toString('16')); 71 | var clients; 72 | bypassBlacklist = bypassBlacklist || false; 73 | if(packet) { 74 | if(this._packetBlackList.indexOf(packet.opcode) == -1 || bypassBlacklist) { 75 | clients = this._bot.server.clients; 76 | for(var key in clients) { 77 | var client; 78 | client = clients[key]; 79 | 80 | if(client.state == this._bot.enums.clientState.LOADING_GAME_WORLD) { 81 | client.packetHoldList.push(packet); 82 | } else { 83 | this._sendPacket(client, packet); 84 | } 85 | } 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /logic/client/character/CharList.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | var EventEmitter = require('events').EventEmitter; 3 | var PacketWriter = require('../../../packet/PacketWriter'); 4 | 5 | module.exports = { 6 | CharList: CharList 7 | }; 8 | 9 | util.inherits(CharList, EventEmitter); 10 | 11 | var $CharList = CharList.prototype; 12 | $CharList.requestCharList = CharList$requestCharList; 13 | $CharList.analyze = CharList$analyze; 14 | $CharList.selectCharacter = CharList$selectCharacter; 15 | $CharList.characterSelected = CharList$characterSelected; 16 | $CharList.confirmSpawn = CharList$confirmSpawn; 17 | 18 | function CharList(bot) { 19 | EventEmitter.call(this); 20 | 21 | this._bot = bot; 22 | this.charList = new Object; 23 | this.charListPacket = null; 24 | 25 | } 26 | 27 | function CharList$requestCharList() { 28 | var p = new PacketWriter(); 29 | p.writeByte(2); 30 | this._bot.client.send(this._bot.opcodes.CLIENT.CHARACTER_LIST, p, false); 31 | } 32 | 33 | function CharList$analyze(packet) { 34 | this.charListPacket = packet; 35 | var charCount, charInfo; 36 | 37 | this.charList = new Object; 38 | if(packet.readByte() == 2) { 39 | if(packet.readByte() == 1) { 40 | charCount = packet.readByte(); 41 | for (var i = 0; i < charCount; i++) { 42 | 43 | //Main data 44 | charInfo = { 45 | model: packet.readDWord(), 46 | name: packet.readString(true), 47 | volume: packet.readByte(), 48 | level: packet.readByte(), 49 | exp: packet.readQWord(), 50 | str: packet.readWord(), 51 | int: packet.readWord(), 52 | statPoints: packet.readWord(), 53 | hp: packet.readDWord(), 54 | mp: packet.readDWord(), 55 | }; 56 | 57 | 58 | // Deletion 59 | if(packet.readByte() == 1) { //If character is deleted 60 | packet.readDWord(); 61 | charInfo.deleted = true; 62 | } else { 63 | charInfo.deleted = false; 64 | } 65 | 66 | packet.readByte(); // Unknown 67 | packet.readByte(); // Unknown 68 | packet.readByte(); // Unknown 69 | 70 | //Items 71 | for (var i = 0; i < packet.readByte(); i++) { 72 | packet.readDWord(); 73 | packet.readByte(); 74 | }; 75 | 76 | //Avatars 77 | for (var i = 0; i < packet.readByte(); i++) { 78 | packet.readDWord(); 79 | packet.readByte(); 80 | }; 81 | 82 | this.charList[charInfo.name] = charInfo; 83 | 84 | }; 85 | } 86 | } 87 | 88 | this.emit('charList', this.charList); 89 | } 90 | 91 | function CharList$selectCharacter(charName) { 92 | 93 | if(this._bot.globals.clientState == this._bot.enums.clientState.WAITING_CHAR_SELECTION) { 94 | if(this.charList[charName]){ 95 | //Save character to settings 96 | this._bot.settings.charName = charName; 97 | var p = new PacketWriter(); 98 | p.writeString(charName); 99 | this._bot.client.send(this._bot.opcodes.CLIENT.CHARACTER_SELECT, p, false); 100 | } else { 101 | this.emit('charListError', 'Cannot select character because given character name is not exist ('+ charName +')'); 102 | } 103 | } else { 104 | this.emit('charListError', 'Cannot select character because client state is not WAITING_CHAR_SELECTION ('+ this._bot.globals.clientState +')'); 105 | } 106 | } 107 | 108 | function CharList$characterSelected(packet) { 109 | if(packet.readByte() == 1) { 110 | //Confirm spawn 111 | this.confirmSpawn(); 112 | //Character selected. Bot in game. 113 | this.emit('characterSelected'); 114 | } 115 | } 116 | 117 | function CharList$confirmSpawn(){ 118 | this._bot.client.send(this._bot.opcodes.CLIENT.CONFIRM_SPAWN, new PacketWriter(), false); 119 | } -------------------------------------------------------------------------------- /logic/client/spawns/SpawnManager.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | var fs = require('fs'); 3 | var hexdump = require('hexdump-nodejs'); 4 | var PacketWriter = require('../../../packet/PacketWriter'); 5 | var functions = require('../../../functions'); 6 | 7 | module.exports = { 8 | SpawnManager: SpawnManager 9 | }; 10 | 11 | var $SpawnManager = SpawnManager.prototype; 12 | $SpawnManager.parseGroupSpawn = SpawnManager$parseGroupSpawn; 13 | $SpawnManager.spawn = SpawnManager$spawn; 14 | $SpawnManager.despawn = SpawnManager$despawn; 15 | 16 | function SpawnManager(bot) { 17 | this._bot = bot; 18 | this.characters = new Object(); 19 | this.gates = new Object(); 20 | this.pets = new Object(); 21 | this.NPCs = new Object(); 22 | this.monsters = new Object(); 23 | this.others = new Object(); 24 | this.items = new Object(); 25 | } 26 | 27 | function SpawnManager$parseGroupSpawn(packet, action, count) { 28 | //var action, count; 29 | // 30 | //count = 1; 31 | //action = 1; 32 | //if(packet.opcode == this._bot.opcodes.SERVER.GROUPSPAWN_DATA) { 33 | // action = this._bot.groupSpawn.action; 34 | // count = this._bot.groupSpawn.count; 35 | //} 36 | 37 | if(action == 1) { 38 | for (var i = 0; i < count; i++) { 39 | this.spawn(packet); 40 | }; 41 | } else { 42 | for (var i = 0; i < count; i++) { 43 | this.despawn(packet); 44 | }; 45 | } 46 | 47 | } 48 | 49 | function SpawnManager$spawn(packet) { 50 | //try { 51 | 52 | var model, charData, itemData; 53 | 54 | model = packet.readDWord(); 55 | charData = this._bot.gameData.chars[model]; 56 | gateData = this._bot.gameData.gates[model]; 57 | itemData = this._bot.gameData.items[model]; 58 | 59 | if(charData !== undefined) { 60 | var type; 61 | type = charData.type; 62 | if(type.contains('CHAR_')) { 63 | this._bot.spawnParser.parseChar(packet, model); 64 | } 65 | //else if(type.contains('_GATE')) { 66 | // this._bot.spawnParser.parseGate(packet, model); 67 | //} 68 | else if(type.contains('COS_')) { 69 | this._bot.spawnParser.parsePet(packet, model); 70 | } 71 | else if(type.contains('NPC_')) { 72 | this._bot.spawnParser.parseNPC(packet, model); 73 | } 74 | else if(type.contains('MOB_')) { 75 | this._bot.spawnParser.parseMonster(packet, model); 76 | } 77 | else { 78 | this._bot.spawnParser.parseOther(packet, model); 79 | } 80 | } else if (gateData !== undefined) { 81 | this._bot.spawnParser.parseGate(packet, model); 82 | } else if (itemData !== undefined) { 83 | this._bot.spawnParser.parseItem(packet, model); 84 | } else { 85 | console.log('Unknown item in SpawnManager$spawn. (model: ' + model + ')'); 86 | //console.log(packet.buffer); 87 | fs.writeFile('log/packet-' + model + '-' + process.hrtime() + '.txt', hexdump(packet.buffer)); 88 | } 89 | 90 | console.log('Characters: ', Object.keys(this.characters).length); 91 | console.log('Gates: ', Object.keys(this.gates).length); 92 | console.log('Monsters: ', Object.keys(this.monsters).length); 93 | console.log('Pets: ', Object.keys(this.pets).length); 94 | console.log('NPCs: ', Object.keys(this.NPCs).length); 95 | console.log('Other: ', Object.keys(this.others).length); 96 | console.log('Items: ', Object.keys(this.items).length); 97 | //} catch(error) { 98 | // console.log('SpawnManager Spawn parse error occured.', error, packet); 99 | //} 100 | } 101 | 102 | function SpawnManager$despawn(packet) { 103 | var id; 104 | id = packet.readDWord(); 105 | if(this.characters[id] !== undefined) { 106 | delete this.characters[id]; 107 | } else if(this.gates[id] !== undefined) { 108 | delete this.gates[id]; 109 | } else if(this.pets[id] !== undefined) { 110 | delete this.pets[id]; 111 | } else if(this.NPCs[id] !== undefined) { 112 | delete this.NPCs[id]; 113 | } else if(this.monsters[id] !== undefined) { 114 | delete this.monsters[id]; 115 | } else if(this.others[id] !== undefined) { 116 | delete this.others[id]; 117 | } else if(this.items[id] !== undefined) { 118 | delete this.items[id]; 119 | } 120 | 121 | console.log('Characters: ', Object.keys(this.characters).length); 122 | console.log('Gates: ', Object.keys(this.gates).length); 123 | console.log('Monsters: ', Object.keys(this.monsters).length); 124 | console.log('Pets: ', Object.keys(this.pets).length); 125 | console.log('NPCs: ', Object.keys(this.NPCs).length); 126 | console.log('Other: ', Object.keys(this.others).length); 127 | console.log('Items: ', Object.keys(this.items).length); 128 | } -------------------------------------------------------------------------------- /logic/client/items/InventoryParser.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | var PacketWriter = require('../../../packet/PacketWriter'); 3 | var functions = require('../../../functions'); 4 | 5 | module.exports = { 6 | InventoryParser: InventoryParser 7 | }; 8 | 9 | var $InventoryParser = InventoryParser.prototype; 10 | $InventoryParser.parse = InventoryParser$parse; 11 | 12 | function InventoryParser(bot) { 13 | this._bot = bot; 14 | } 15 | 16 | function InventoryParser$parse() { 17 | var tempItem, item, itemId, itemType, itemName; 18 | 19 | tempItem = { 20 | model: null, 21 | type: null, 22 | name: null, 23 | plus: null, 24 | durability: null, 25 | amount: null, 26 | modelLevel: null, 27 | modelName: null, 28 | model2: null, 29 | }; 30 | 31 | this._bot.charData.charDataPacket.readDWord(); //unknown 32 | itemId = this._bot.charData.charDataPacket.readDWord(); 33 | item = this._bot.gameData.items[itemId]; 34 | itemType = item.type || undefined; 35 | itemName = item.name || undefined; 36 | 37 | tempItem.model = itemId; 38 | tempItem.type = itemType; 39 | tempItem.name = itemName; 40 | if( itemType.startsWith('ITEM_CH') || 41 | itemType.startsWith('ITEM_EU') || 42 | itemType.startsWith('ITEM_MALL_AVATAR') || 43 | itemType.startsWith('ITEM_ETC_E060529_GOLDDRAGONFLAG') || 44 | itemType.startsWith('ITEM_EVENT_CH') || 45 | itemType.startsWith('ITEM_EVENT_EU') || 46 | itemType.startsWith('ITEM_EVENT_AVATAR_W_NASRUN') || 47 | itemType.startsWith('ITEM_EVENT_AVATAR_M_NASRUN') || 48 | itemType.startsWith('ITEM_EVENT_E081126_SILKROAD_PLAG')) { 49 | 50 | var itemPlus, durability, blueAmount; 51 | 52 | itemPlus = this._bot.charData.charDataPacket.readByte(); 53 | this._bot.charData.charDataPacket.readQWord(); 54 | durability = this._bot.charData.charDataPacket.readDWord(); 55 | blueAmount = this._bot.charData.charDataPacket.readByte(); 56 | for (var i = 0; i < blueAmount; i++) { 57 | this._bot.charData.charDataPacket.readDWord(); 58 | this._bot.charData.charDataPacket.readDWord(); 59 | }; 60 | 61 | this._bot.charData.charDataPacket.readWord(); 62 | this._bot.charData.charDataPacket.readWord(); 63 | //this._bot.charData.charDataPacket.readWord(); 64 | 65 | tempItem.plus = itemPlus; 66 | tempItem.durability = durability; 67 | tempItem.amount = 1; 68 | 69 | } else if( (itemType.startsWith("ITEM_COS") && itemType.contains("SILK")) || 70 | (itemType.startsWith("ITEM_EVENT_COS") && !itemType.contains("_C_"))) { 71 | 72 | var flag; 73 | 74 | flag = this._bot.charData.charDataPacket.readByte(); 75 | if(flag == 2 || flag == 3 || flag == 4) { // 0x03 Alive - 0x04 Dead - 0x02 Summoned 76 | tempItem.modelLevel = this._bot.charData.charDataPacket.readDWord(); 77 | tempItem.modelName = this._bot.charData.charDataPacket.readString(true); 78 | this._bot.charData.charDataPacket.readByte(); 79 | if(this._bot.gameData.types.attackPetItems.indexOf(itemType) == -1){ 80 | this._bot.charData.charDataPacket.readDWord(); 81 | } 82 | } 83 | 84 | tempItem.plus = 0; 85 | tempItem.durability = 0; 86 | tempItem.amount = 1; 87 | 88 | } else if(this._bot.gameData.petTypes.grabPetItems.indexOf(itemName) != -1 || this._bot.gameData.petTypes.attackPetItems.indexOf(itemName) != -1) { 89 | var flag; 90 | 91 | flag = this._bot.charData.charDataPacket.readByte(); 92 | 93 | if(flag == 2 || flag == 3 || flag == 4) { // 0x03 Alive - 0x04 Dead - 0x02 Summoned 94 | tempItem.model2 = this._bot.charData.charDataPacket.readDWord(); 95 | tempItem.modelName = this._bot.charData.charDataPacket.readString(true); 96 | if(this._bot.gameData.types.attackPetItems.indexOf(itemType) == -1){ 97 | this._bot.charData.charDataPacket.readDWord(); 98 | } 99 | this._bot.charData.charDataPacket.readByte(); 100 | } 101 | 102 | tempItem.plus = 0; 103 | tempItem.durability = 0; 104 | tempItem.amount = 1; 105 | 106 | } else if(itemType == 'ITEM_ETC_TRANS_MONSTER') { 107 | this._bot.charData.charDataPacket.readDWord(); 108 | tempItem.plus = 0; 109 | tempItem.durability = 0; 110 | tempItem.amount = 1; 111 | 112 | } else if(itemType.startsWith('ITEM_MALL_MAGIC_CUBE')) { 113 | this._bot.charData.charDataPacket.readDWord(); 114 | tempItem.plus = 0; 115 | tempItem.durability = 0; 116 | tempItem.amount = 1; 117 | 118 | } else { 119 | var count; 120 | count = this._bot.charData.charDataPacket.readWord(); 121 | if(itemType.contains('ITEM_ETC_ARCHEMY_ATTRSTONE') || itemType.contains('ITEM_ETC_ARCHEMY_MAGICSTONE')) { 122 | this._bot.charData.charDataPacket.readByte(); 123 | } 124 | 125 | tempItem.plus = 0; 126 | tempItem.durability = 0; 127 | tempItem.amount = count; 128 | 129 | } 130 | return tempItem; 131 | } -------------------------------------------------------------------------------- /gamedata/GameData.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | var fs = require('fs'); 3 | var functions = require('../functions'); 4 | 5 | module.exports = { 6 | GameData: GameData 7 | }; 8 | 9 | var $GameData = GameData.prototype; 10 | $GameData.loadData = GameData$loadData; 11 | $GameData.initPetTypes = GameData$initPetTypes; 12 | 13 | function GameData(bot) { 14 | this._bot = bot; 15 | 16 | this.items = new Object(); 17 | 18 | this.skills = new Object(); 19 | 20 | this.chars = new Object(); 21 | 22 | this.gates = new Object(); 23 | 24 | this.petTypes = { 25 | grabPets: [], 26 | grabPetItems: [], 27 | attackPets: [], 28 | attackPetItems: [], 29 | }; 30 | 31 | this.loadData(); 32 | this.initPetTypes(); 33 | } 34 | 35 | function GameData$loadData() { 36 | var lines, line, lineItems; 37 | 38 | // load itemdata 39 | /* 40 | lines = fs.readFileSync('./gamedata/data/itemdata.txt').toString().split('\n'); 41 | 42 | for (var i = 0; i < lines.length; i++) { 43 | line = lines[i]; 44 | if(!line.startsWith('//')) { 45 | lineItems = line.split(','); 46 | this.items.id.push(parseInt(lineItems[0])); 47 | this.items.type.push(lineItems[1] || 'ITEM_UNKNOWN'); 48 | this.items.name.push(lineItems[2] || 0); 49 | this.items.level.push(lineItems[3] || 0); 50 | this.items.maxStack.push(lineItems[4] || 1); 51 | this.items.durability.push(lineItems[5] || 0); 52 | } 53 | }; 54 | */ 55 | // load itemdata 56 | lines = fs.readFileSync('./gamedata/data/itemdata.txt').toString().split('\n'); 57 | 58 | for (var i = 0; i < lines.length; i++) { 59 | line = lines[i]; 60 | if(!line.startsWith('//')) { 61 | var tempObj, id; 62 | tempObj = new Object(); 63 | lineItems = line.split(','); 64 | 65 | id = parseInt(lineItems[0]); 66 | tempObj.id = id; 67 | tempObj.type = lineItems[1] || 'ITEM_UNKNOWN'; 68 | tempObj.name = lineItems[2] || 0; 69 | tempObj.level = lineItems[3] || 0; 70 | tempObj.maxStack = lineItems[4] || 1; 71 | tempObj.durability = lineItems[5] || 0; 72 | this.items[id] = tempObj; 73 | } 74 | }; 75 | 76 | // load skilldata 77 | lines = fs.readFileSync('./gamedata/data/skilldata.txt').toString().split('\n'); 78 | 79 | for (var i = 0; i < lines.length; i++) { 80 | line = lines[i]; 81 | if(!line.startsWith('//')) { 82 | var tempObj, id; 83 | tempObj = new Object(); 84 | lineItems = line.split(','); 85 | 86 | id = parseInt(lineItems[0]); 87 | tempObj.id = id; 88 | tempObj.type = lineItems[1] || 'SKILL_UNKNOWN'; 89 | tempObj.name = lineItems[2] || 0; 90 | tempObj.castTime = lineItems[3] || 0; 91 | tempObj.coolDown = lineItems[4] || 1; 92 | tempObj.reqMP = lineItems[5] || 0; 93 | this.skills[id] = tempObj; 94 | } 95 | }; 96 | 97 | // load chardata 98 | lines = fs.readFileSync('./gamedata/data/chardata.txt').toString().split('\n'); 99 | 100 | for (var i = 0; i < lines.length; i++) { 101 | line = lines[i]; 102 | if(!line.startsWith('//')) { 103 | var tempObj, id; 104 | tempObj = new Object(); 105 | lineItems = line.split(','); 106 | 107 | id = parseInt(lineItems[0]); 108 | tempObj.id = id; 109 | tempObj.type = lineItems[1] || 'CHAR_UNKNOWN'; 110 | tempObj.name = lineItems[2] || 0; 111 | tempObj.level = lineItems[3] || 0; 112 | tempObj.hp = lineItems[4] || 0; 113 | this.chars[id] = tempObj; 114 | } 115 | }; 116 | 117 | // load teleportbuilding 118 | lines = fs.readFileSync('./gamedata/data/teleportbuilding.txt').toString().split('\n'); 119 | 120 | for (var i = 0; i < lines.length; i++) { 121 | line = lines[i]; 122 | if(!line.startsWith('//')) { 123 | var tempObj, id; 124 | tempObj = new Object(); 125 | lineItems = line.split(','); 126 | 127 | id = parseInt(lineItems[0]); 128 | tempObj.id = id; 129 | tempObj.type = lineItems[1] || 'STORE_UNKNOWN_GATE'; 130 | tempObj.name = lineItems[2] || 0; 131 | tempObj.level = lineItems[3] || 0; 132 | tempObj.hp = lineItems[4] || 0; 133 | this.gates[id] = tempObj; 134 | } 135 | }; 136 | } 137 | 138 | function GameData$initPetTypes(){ 139 | //attack pets 140 | this.petTypes.attackPets.push('COS_P_BEAR'); 141 | this.petTypes.attackPets.push('COS_P_FOX'); 142 | this.petTypes.attackPets.push('COS_P_PENGUIN'); 143 | this.petTypes.attackPets.push('COS_P_WOLF_WHITE_SMALL'); 144 | this.petTypes.attackPets.push('COS_P_WOLF_WHITE'); 145 | this.petTypes.attackPets.push('COS_P_WOLF'); 146 | this.petTypes.attackPets.push('COS_P_JINN'); 147 | this.petTypes.attackPets.push('COS_P_KANGAROO'); 148 | this.petTypes.attackPets.push('COS_P_RAVEN'); 149 | 150 | //attack pet items 151 | this.petTypes.attackPetItems.push('ITEM_COS_P_BEAR_SCROLL'); 152 | this.petTypes.attackPetItems.push('ITEM_COS_P_FOX_SCROLL'); 153 | this.petTypes.attackPetItems.push('ITEM_COS_P_PENGUIN_SCROLL'); 154 | this.petTypes.attackPetItems.push('ITEM_COS_P_FLUTE_WHITE_SMALL'); 155 | this.petTypes.attackPetItems.push('ITEM_COS_P_FLUTE_WHITE'); 156 | this.petTypes.attackPetItems.push('ITEM_COS_P_FLUTE'); 157 | this.petTypes.attackPetItems.push('ITEM_COS_P_FLUTE_SILK'); 158 | this.petTypes.attackPetItems.push('ITEM_COS_P_JINN_SCROLL'); 159 | this.petTypes.attackPetItems.push('ITEM_COS_P_KANGAROO_SCROLL'); 160 | this.petTypes.attackPetItems.push('ITEM_COS_P_RAVEN_SCROLL'); 161 | 162 | //grab pets 163 | this.petTypes.grabPets.push('COS_P_SPOT_RABBIT'); 164 | this.petTypes.grabPets.push('COS_P_RABBIT'); 165 | this.petTypes.grabPets.push('COS_P_GGLIDER'); 166 | this.petTypes.grabPets.push('COS_P_MYOWON'); 167 | this.petTypes.grabPets.push('COS_P_SEOWON'); 168 | this.petTypes.grabPets.push('COS_P_RACCOONDOG'); 169 | this.petTypes.grabPets.push('COS_P_CAT'); 170 | this.petTypes.grabPets.push('COS_P_BROWNIE'); 171 | this.petTypes.grabPets.push('COS_P_PINKPIG'); 172 | this.petTypes.grabPets.push('COS_P_GOLDPIG'); 173 | this.petTypes.grabPets.push('COS_P_WINTER_SNOWMAN'); 174 | 175 | //grab pet items 176 | this.petTypes.grabPetItems.push('ITEM_COS_P_SPOT_RABBIT_SCROLL'); 177 | this.petTypes.grabPetItems.push('ITEM_COS_P_RABBIT_SCROLL'); 178 | this.petTypes.grabPetItems.push('ITEM_COS_P_RABBIT_SCROLL_SILK'); 179 | this.petTypes.grabPetItems.push('ITEM_COS_P_GGLIDER_SCROLL'); 180 | this.petTypes.grabPetItems.push('ITEM_COS_P_MYOWON_SCROLL'); 181 | this.petTypes.grabPetItems.push('ITEM_COS_P_SEOWON_SCROLL'); 182 | this.petTypes.grabPetItems.push('ITEM_COS_P_RACCOONDOG_SCROLL'); 183 | this.petTypes.grabPetItems.push('ITEM_COS_P_CAT_SCROLL'); 184 | this.petTypes.grabPetItems.push('ITEM_COS_P_BROWNIE_SCROLL'); 185 | this.petTypes.grabPetItems.push('ITEM_COS_P_PINKPIG_SCROLL'); 186 | this.petTypes.grabPetItems.push('ITEM_EVENT_COS_P_PINKPIG_SCROLL'); 187 | this.petTypes.grabPetItems.push('ITEM_COS_P_GOLDPIG_SCROLL'); 188 | this.petTypes.grabPetItems.push('ITEM_COS_P_GOLDPIG_SCROLL_SILK'); 189 | this.petTypes.grabPetItems.push('ITEM_EVENT_COS_P_GOLDPIG_SCROLL'); 190 | this.petTypes.grabPetItems.push('ITEM_COS_P_WINTER_SNOWMAN_SCROLL'); 191 | this.petTypes.grabPetItems.push('ITEM_EVENT_COS_P_WINTER_SNOWMAN_SCROLL'); 192 | } 193 | 194 | -------------------------------------------------------------------------------- /connections/Client.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | var fs = require('fs'); 3 | var hexdump = require('hexdump-nodejs'); 4 | var EventEmitter = require('events').EventEmitter; 5 | var net = require('net'); 6 | var Security = require('../security/Security'); 7 | var PacketReader = require('../packet/PacketReader'); 8 | var PacketWriter = require('../packet/PacketWriter'); 9 | 10 | module.exports = { 11 | connect: connect, 12 | Client: Client 13 | }; 14 | 15 | function connect(options) { 16 | return new Client(options); 17 | } 18 | 19 | util.inherits(Client, EventEmitter); 20 | 21 | var $Client = Client.prototype; 22 | $Client._connect = Client$_connect; 23 | $Client.end = Client$end; 24 | $Client.reconnect = Client$reconnect; 25 | $Client.send = Client$send; 26 | $Client._processData = Client$_processData; 27 | $Client._process = Client$_process; 28 | $Client._handlePackets = Client$_handlePackets; 29 | $Client._handshake = Client$_handshake; 30 | 31 | function Client(options) { 32 | EventEmitter.call(this); 33 | 34 | options = this.options = { 35 | host: options && options.host, 36 | port: options && options.port || 15779 37 | }; 38 | 39 | 40 | this.connection = null; 41 | 42 | this.security = null; 43 | 44 | this._stored = { 45 | buffer: null, 46 | length: 0, 47 | }; 48 | 49 | this._bound = { 50 | onError: onError.bind(this), 51 | onClose: onClose.bind(this), 52 | onReadable: onReadable.bind(this) 53 | }; 54 | 55 | this._connect(options); 56 | } 57 | 58 | function Client$_connect(options) { 59 | var conn, bound; 60 | 61 | this.security = new Security(); 62 | 63 | bound = this._bound; 64 | conn = this.connection = net.connect(options); 65 | conn.on('error', bound.onError); 66 | conn.on('close', bound.onClose); 67 | conn.on('readable', bound.onReadable); 68 | } 69 | 70 | function Client$end() { 71 | this.connection.end(); 72 | this.connection = null; 73 | } 74 | 75 | function Client$reconnect(options){ 76 | if(this.connection){ 77 | this.connection.end(); 78 | this.connection = null; 79 | } 80 | 81 | this._connect(options); 82 | 83 | } 84 | 85 | function Client$send(opcode, packet, encrypted) { 86 | var packet; 87 | 88 | console.log('[CLIENT][C->S] '+ opcode.toString('16')); 89 | packet = this.security.formatPacket(opcode, packet.getBytes(), encrypted); 90 | this.connection.write(packet); 91 | } 92 | 93 | function Client$_processData(data) { 94 | console.log('PROCESS DATA CHECKPOINT'); 95 | var pointer = 0; 96 | var tmpLength = data.length; 97 | var buffers = []; 98 | var totalBuffer; 99 | fs.appendFile('log/client.log', '================================\n'); 100 | fs.appendFile('log/client.log', 'tmpLength: ' + tmpLength + '\n'); 101 | 102 | if (this._stored.buffer.length > 0) { 103 | fs.appendFile('log/client.log', 'stored: ' + this._stored.buffer.length + '\n'); 104 | totalBuffer = new Buffer(this._stored.buffer.length + data.length); 105 | this._stored.buffer.copy(totalBuffer); 106 | data.copy(totalBuffer, this._stored.buffer.length); 107 | tmpLength = this._stored.buffer.length + data.length; 108 | this._stored.length = 0; 109 | } 110 | 111 | while (tmpLength > 0) { 112 | var encrypted = false; 113 | var realSize = 0; 114 | var packetSize = data[pointer + 1] << 8 | data[pointer]; 115 | if ((packetSize & 0x8000) > 0) { 116 | packetSize &= 0x7fff; 117 | realSize = packetSize; 118 | encrypted = true; 119 | packetSize = 2 + this.security.getOutputLength(packetSize + 4); 120 | } 121 | else { 122 | packetSize += 6; 123 | } 124 | 125 | if (packetSize > tmpLength) { 126 | this._stored.buffer = new Buffer(tmpLength); 127 | data.copy(this._stored.buffer, 0, pointer); 128 | this._stored.buffer.length = tmpLength; 129 | tmpLength = 0; 130 | } 131 | else { 132 | var currentBuffer = new Buffer(packetSize); 133 | data.copy(currentBuffer, 0, pointer, pointer + packetSize); 134 | var tmp = { 135 | size: packetSize, 136 | buffer: currentBuffer, 137 | encry: encrypted, 138 | real: realSize 139 | }; 140 | buffers.push(tmp); 141 | pointer += packetSize; 142 | tmpLength -= packetSize; 143 | 144 | } 145 | } 146 | 147 | for (var i = 0; i < buffers.length; i++) { 148 | fs.appendFile('log/client.log', 'buffer size: ' + buffers[i].size + '\n'); 149 | fs.appendFile('log/client.log', 'buffer encry: ' + buffers[i].encry + '\n'); 150 | fs.appendFile('log/client.log', 'buffer real size: ' + buffers[i].real + '\n'); 151 | fs.appendFile('log/client.log', '--------------------------\n'); 152 | 153 | }; 154 | fs.appendFile('log/client.log', '================================\n'); 155 | 156 | if (buffers.length > 0) { 157 | this._process(buffers); 158 | } 159 | } 160 | 161 | function Client$_process(buffers) { 162 | console.log('PROCESS CHECKPOINT'); 163 | for (var i = 0; i < buffers.length; i++) { 164 | if (buffers[i].encry) { 165 | var decrypted = this.security.decode(buffers[i].buffer, 2, buffers[i].size - 2); 166 | var real = new Buffer(2 + buffers[i].size); 167 | real.writeUInt16LE(buffers[i].real, 0); 168 | decrypted.copy(real, 2); 169 | var p = new PacketReader(real); 170 | p.encrypted = true; 171 | fs.appendFile('log/client.log', '================================\n'); 172 | fs.appendFile('log/client.log', 'packet: ' + p.opcode.toString('16') + '\n'); 173 | fs.appendFile('log/client.log', '================================\n'); 174 | this._handlePackets(p); 175 | } 176 | else { 177 | var p = new PacketReader(buffers[i].buffer); 178 | p.encrypted = false; 179 | fs.appendFile('log/client.log', '================================\n'); 180 | fs.appendFile('log/client.log', 'packet: ' + p.opcode.toString('16') + '\n'); 181 | fs.appendFile('log/client.log', '================================\n'); 182 | this._handlePackets(p); 183 | } 184 | } 185 | } 186 | 187 | function Client$_handlePackets(packet) { 188 | console.log('[CLIENT][S->C] ' + packet.opcode.toString('16')); 189 | if (packet.opcode === 0x5000) { 190 | this._handshake(packet); 191 | } else { 192 | this.emit('packet', packet); 193 | } 194 | } 195 | 196 | function Client$_handshake(packet) { 197 | var responsePackets; 198 | 199 | responsePackets = this.security.handshake(packet); 200 | if(responsePackets) { 201 | for (var i = 0; i < responsePackets.length; i++) { 202 | this.send(responsePackets[i].opcode, responsePackets[i].packet, responsePackets[i].encrypted); 203 | }; 204 | } 205 | 206 | /* 207 | var sec; 208 | 209 | sec = this.security; 210 | packet.pointer = 6; 211 | if (packet.size == 0x25) { 212 | console.log("Handshake starting"); 213 | //this.send(0x5000, new PacketWriter(sec.handshakeE(packet)), false); 214 | console.log(new PacketWriter(sec.handshakeE(packet))); 215 | } 216 | else if (packet.size == 9) { 217 | this.connection.write(sec.handshake10(packet)); 218 | 219 | var resp = new PacketWriter(); 220 | resp.writeString("SR_Client"); 221 | resp.writeByte(0); 222 | this.send(0x2001, resp, true); 223 | 224 | } 225 | */ 226 | } 227 | 228 | function onError(error) { 229 | this.emit('error', error); 230 | } 231 | 232 | function onClose(hadError) { 233 | this.emit('close', hadError); 234 | } 235 | 236 | function onReadable() { 237 | var conn, chunk; 238 | 239 | conn = this.connection; 240 | if (conn) { 241 | chunk = this.connection.read(); 242 | } 243 | 244 | if (chunk) { 245 | fs.appendFile('log/client.log', hexdump(chunk)); 246 | this._processData(chunk); 247 | } 248 | } 249 | 250 | 251 | 252 | 253 | 254 | -------------------------------------------------------------------------------- /connections/Server.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | var EventEmitter = require('events').EventEmitter; 3 | var net = require('net'); 4 | var Security = require('../security/Security'); 5 | var PacketReader = require('../packet/PacketReader'); 6 | var PacketWriter = require('../packet/PacketWriter'); 7 | 8 | module.exports = { 9 | listen: listen, 10 | Server: Server 11 | }; 12 | 13 | function listen(bot) { 14 | return new Server(bot); 15 | } 16 | 17 | util.inherits(Server, EventEmitter); 18 | 19 | var $Server = Server.prototype; 20 | $Server._listen = Server$_listen; 21 | $Server.send = Server$send; 22 | $Server.sendAll = Server$sendAll; 23 | $Server._processData = Server$_processData; 24 | $Server._process = Server$_process; 25 | $Server._handlePackets = Server$_handlePackets; 26 | $Server._handshake = Server$_handshake; 27 | 28 | function Server(bot) { 29 | EventEmitter.call(this); 30 | 31 | this._bot = bot; 32 | 33 | this.clients = new Object(); 34 | 35 | this.listener = null; 36 | this.port = 9000; 37 | 38 | this._stored = { 39 | buffer: [], 40 | length: 0 41 | }; 42 | 43 | this._bound = { 44 | onListening: onListening.bind(this), 45 | onConnection: onConnection.bind(this), 46 | onClose: onClose.bind(this), 47 | onError: onError.bind(this), 48 | 49 | onSocketReadable: onSocketReadable.bind(this), 50 | onSocketError: onSocketError.bind(this), 51 | onSocketClose: onSocketClose.bind(this), 52 | }; 53 | 54 | this._listen(); 55 | } 56 | 57 | function Server$_listen() { 58 | var listener, bound; 59 | 60 | bound = this._bound; 61 | listener = this.listener = net.createServer().listen(this.port); 62 | listener.on('listening', bound.onListening); 63 | listener.on('connection', bound.onConnection); 64 | listener.on('close', bound.onClose); 65 | listener.on('error', bound.onError); 66 | } 67 | 68 | function Server$send(client, opcode, packet, encrypted) { 69 | var p; 70 | 71 | //console.log('[SERVER][S->C] '+ opcode.toString('16')); 72 | p = client.security.formatPacket(opcode, packet.getBytes(), encrypted); 73 | client.socket.write(p); 74 | 75 | } 76 | 77 | function Server$sendAll(opcode, packet, encrypted) { 78 | //if(Object.keys(this.clients).length) { 79 | // console.log('[SERVER][ALL][S->C] '+ opcode.toString('16')); 80 | //} 81 | for(var key in this.clients) { 82 | var client, p; 83 | client = this.clients[key]; 84 | p = client.security.formatPacket(opcode, packet.getBytes(), encrypted); 85 | client.socket.write(p); 86 | }; 87 | } 88 | 89 | function Server$_processData(data, length, client) { 90 | var pointer = 0; 91 | var tmpLength = data.length; 92 | var buffers = []; 93 | var bufferCount = 0; 94 | 95 | var totalBuffer = {}; 96 | totalBuffer = data; 97 | 98 | if (this._stored.length > 0) { 99 | totalBuffer = new Buffer(this._stored.length + length); 100 | this._stored.buffer.copy(totalBuffer); 101 | data.copy(totalBuffer, this._stored.length); 102 | tmplength = this._stored.length + length; 103 | this._stored.length = 0; 104 | } 105 | else { 106 | totalBuffer = data; 107 | } 108 | 109 | while (tmpLength > 0) { 110 | var encrypted = false; 111 | var realsize = 0; 112 | var packetsize = totalBuffer[pointer + 1] << 8 | totalBuffer[pointer]; 113 | if ((packetsize & 0x8000) > 0) { 114 | packetsize &= 0x7fff; 115 | realsize = packetsize; 116 | encrypted = true; 117 | packetsize = 2 + client.security.getOutputLength(packetsize + 4); 118 | } 119 | else { 120 | packetsize += 6; 121 | } 122 | 123 | if (packetsize > tmpLength) { 124 | this._stored.buffer = new Buffer(tmpLength); 125 | totalBuffer.copy(this._stored.buffer, 0, pointer); 126 | this._stored.length = tmpLength; 127 | tmpLength = 0; 128 | } 129 | else { 130 | var currentBuffer = new Buffer(packetsize); 131 | totalBuffer.copy(currentBuffer, 0, pointer, pointer + packetsize); 132 | var tmp = { 133 | size: packetsize, 134 | buffer: currentBuffer, 135 | encry: encrypted, 136 | real: realsize 137 | }; 138 | 139 | buffers.push(tmp); 140 | bufferCount++; 141 | pointer += packetsize; 142 | tmpLength -= packetsize; 143 | 144 | } 145 | } 146 | 147 | if (bufferCount > 0) { 148 | this._process(buffers, bufferCount, client); 149 | } 150 | } 151 | 152 | function Server$_process(buffers, length, client) { 153 | for (var i = 0; i < length; i++) { 154 | if (buffers[i].encry) { 155 | var decrypted = client.security.decode(buffers[i].buffer, 2, buffers[i].size - 2); 156 | var real = new Buffer(2 + buffers[i].size); 157 | real.writeUInt16LE(buffers[i].real, 0); 158 | decrypted.copy(real, 2); 159 | var p = new PacketReader(real); 160 | p.encrypted = true; 161 | this._handlePackets(p, client); 162 | } 163 | else { 164 | var p = new PacketReader(buffers[i].buffer); 165 | p.encrypted = false; 166 | this._handlePackets(p, client); 167 | } 168 | } 169 | } 170 | 171 | function Server$_handlePackets(packet, client) { 172 | console.log('[SERVER][C->S] ' + packet.opcode.toString('16')); 173 | if (packet.opcode === 0x5000 || packet.opcode === 0x9000) { 174 | this._handshake(packet, client); 175 | } else { 176 | this.emit('packet', packet, client); 177 | } 178 | } 179 | 180 | function Server$_handshake(packet, client) { 181 | var responsePackets; 182 | responsePackets = client.security.handshake(packet); 183 | if(responsePackets) { 184 | for (var i = 0; i < responsePackets.length; i++) { 185 | this.send(client, responsePackets[i].opcode, responsePackets[i].packet, responsePackets[i].encrypted); 186 | }; 187 | } 188 | } 189 | 190 | function onListening() { 191 | this.emit('listening', this.port); 192 | } 193 | 194 | function onConnection(socket) { 195 | var client, socketIndex, bound; 196 | 197 | bound = this._bound; 198 | 199 | client = new Object(); 200 | client.socket = socket; 201 | client.security = new Security(); 202 | client.state = this._bot.enums.clientState.OFFLINE; 203 | client.packetHoldList = []; 204 | 205 | socketIndex = socket.remoteAddress + ':' + socket.remotePort; 206 | 207 | this.clients[socketIndex] = client; 208 | 209 | socket.on('readable', function () { 210 | bound.onSocketReadable(client); 211 | }); 212 | socket.on('error', function (error) { 213 | bound.onSocketError(error, client); 214 | }); 215 | socket.on('close', function (hadError) { 216 | bound.onSocketClose(hadError, socket); 217 | }); 218 | 219 | //Generate and send security to client 220 | var response; 221 | response = client.security.generateSecurity(false, false, false); 222 | this.send(client, 0x5000, response, false); 223 | 224 | //Emit 225 | this.emit('connection', client); 226 | } 227 | 228 | function onClose(hadError, client) { 229 | console.log('Server close', hadError); 230 | this.emit('close', hadError); 231 | } 232 | 233 | function onError(error) { 234 | console.log('Server error', error); 235 | this.emit('error', error); 236 | } 237 | 238 | function onSocketReadable(client) { 239 | var chunk; 240 | 241 | if (client.socket) { 242 | chunk = client.socket.read(); 243 | } 244 | 245 | if (chunk) { 246 | this._processData(chunk, chunk.length, client); 247 | } 248 | } 249 | 250 | function onSocketError(error, client) { 251 | console.log('Server socket error', error); 252 | this.emit('socketError', error, client); 253 | } 254 | 255 | function onSocketClose(hadError, socket) { 256 | //Remove client from clients object 257 | for(var key in this.clients) { 258 | if(this.clients[key].socket == socket) { 259 | this.clients[key].socket.destroy(); 260 | delete this.clients[key]; 261 | } 262 | } 263 | 264 | console.log('Server socket close', hadError); 265 | this.emit('socketClose', hadError); 266 | } 267 | 268 | 269 | 270 | -------------------------------------------------------------------------------- /logic/client/login/Login.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | var EventEmitter = require('events').EventEmitter; 3 | var PacketWriter = require('../../../packet/PacketWriter'); 4 | 5 | module.exports = { 6 | Login: Login 7 | }; 8 | 9 | util.inherits(Login, EventEmitter); 10 | 11 | var $Login = Login.prototype; 12 | $Login.identify = Login$identify; 13 | $Login.serverList = Login$serverList; 14 | $Login.captchaRequest = Login$captchaRequest; 15 | $Login.sendLogin = Login$sendLogin; 16 | $Login.autoLogin = Login$autoLogin; 17 | $Login.loginResponse = Login$loginResponse; 18 | $Login.gameLoginResponse = Login$gameLoginResponse; 19 | 20 | function Login(bot) { 21 | EventEmitter.call(this); 22 | 23 | this._bot = bot; 24 | this.srvList = null; 25 | this.serverListPacket = null; 26 | } 27 | 28 | function Login$identify(packet) { 29 | var server; 30 | server = packet.readString(true); 31 | if (server == this._bot.enums.serverType.GATEWAY_SERVER) { 32 | var resp = new PacketWriter(); 33 | resp.writeByte(this._bot.settings.locale); 34 | resp.writeString("SR_Client"); 35 | resp.writeDWord(this._bot.settings.version); 36 | this._bot.client.send(this._bot.opcodes.CLIENT.PATCH_REQUEST, resp, true); 37 | 38 | var b = new PacketWriter(); 39 | this._bot.client.send(this._bot.opcodes.CLIENT.REQUEST_SERVER_LIST, b, true); 40 | 41 | this.emit('identified', server); 42 | } else if (server == this._bot.enums.serverType.AGENT_SERVER) { 43 | var resp = new PacketWriter(); 44 | resp.writeDWord(this._bot.globals.sessionId); 45 | resp.writeString(this._bot.settings.username); 46 | resp.writeString(this._bot.settings.password); 47 | resp.writeByte(this._bot.settings.locale); //locale 48 | resp.writeDWord(0); 49 | resp.writeWord(0); 50 | this._bot.client.send(this._bot.opcodes.CLIENT.GAME_LOGIN, resp, true); 51 | 52 | this.emit('identified', server); 53 | } 54 | } 55 | 56 | function Login$serverList(packet) { 57 | var serverList, server, newServer, id, name, ratio, state, c, total; 58 | 59 | //Save this packet for incoming game client connections (server emulation) 60 | this.serverListPacket = packet; 61 | 62 | total = 1; 63 | serverList = [] 64 | 65 | newServer = packet.readByte(); 66 | 67 | while(newServer == 1) { 68 | id = packet.readByte(); 69 | name = packet.readString(true); 70 | newServer = packet.readByte(); 71 | } 72 | 73 | newServer = packet.readByte(); 74 | 75 | while(newServer == 1) { 76 | 77 | id = ratio = cur = max = c = null; 78 | 79 | id = packet.readWord(); 80 | 81 | if(this._bot.settings.locale == 18) { // ISRO 82 | name = packet.readString(true); 83 | ratio = packet.readFloat(); 84 | 85 | c = name.charAt(0); 86 | name = name.substring(1); 87 | cur = Math.round(ratio * 3500.0); 88 | total += cur; 89 | } else { // Other versions 90 | name = packet.readString(true); 91 | cur = packet.readWord(); 92 | max = packet.readWord(); 93 | } 94 | 95 | server = { 96 | serverId: id, 97 | name: name, 98 | ratio: ratio || null, 99 | c: c || null, 100 | cur: cur || null, 101 | max: max || null, 102 | } 103 | 104 | serverList.push(server); 105 | 106 | state = packet.readByte(); 107 | 108 | // csro/vsro extra bytes 109 | if(this._bot.settings.locale == 4 || this._bot.settings.locale == 22){ 110 | if(packet.readByte() == 1){ 111 | packet.readByte(); 112 | } 113 | } 114 | 115 | newServer = packet.readByte(); 116 | } 117 | 118 | this.srvList = serverList; 119 | 120 | this.emit('serverList', serverList); 121 | } 122 | 123 | function Login$captchaRequest(packet) { 124 | 125 | var p = new PacketWriter(); 126 | p.writeString(""); 127 | this._bot.client.send(this._bot.opcodes.CLIENT.CAPTCHA_REPLY, p, true); 128 | 129 | } 130 | 131 | function Login$sendLogin(username, password, serverId) { 132 | this._bot.settings.username = username; 133 | this._bot.settings.password = password; 134 | this._bot.settings.serverId = serverId; 135 | 136 | if(this._bot.globals.clientState == this._bot.enums.clientState.WAITING_LOGIN) { 137 | var p = new PacketWriter(); 138 | p.writeByte(this._bot.settings.locale); 139 | p.writeString(this._bot.settings.username); 140 | p.writeString(this._bot.settings.password); 141 | p.writeWord(this._bot.settings.serverId); 142 | this._bot.client.send(this._bot.opcodes.CLIENT.LOGIN, p, true); 143 | } else { 144 | this.emit('loginError', 'Cannot send login packet because client state is not WAITING_LOGIN ('+ this._bot.globals.clientState +')'); 145 | } 146 | } 147 | 148 | function Login$autoLogin() { 149 | if(this._bot.settings.autologin) { 150 | if(this._bot.settings.username && this._bot.settings.password && this._bot.settings.serverId){ 151 | this.sendLogin(this._bot.settings.username, this._bot.settings.password, this._bot.settings.serverId); 152 | } 153 | } 154 | } 155 | 156 | function Login$loginResponse(packet){ 157 | var code, subcode, sessionId, host, port, maxTry, curTry, reason, date, emitResp; 158 | 159 | code = packet.readByte(); 160 | 161 | if(code == 1) { 162 | this._bot.globals.sessionId = sessionId = packet.readDWord(); 163 | host = packet.readString(true); 164 | port = packet.readWord(); 165 | 166 | emitResp = { 167 | code: code, 168 | host: host, 169 | port: port, 170 | sessionId: sessionId, 171 | } 172 | 173 | //Send hardcoded success 174 | //this._bot.serverLogic.sendHardcodedLoginSuccessPacket(); 175 | 176 | this.emit('loginResponse', emitResp); 177 | 178 | } else { 179 | subcode = packet.readByte(); 180 | if(subcode == 1) { 181 | //Wrong ID/PW 182 | 183 | this._bot.globals.loginMaxTry = maxTry = packet.readDWord(); 184 | this._bot.globals.loginCurTry = curTry = packet.readDWord(); 185 | 186 | emitResp = { 187 | code: code, 188 | subcode: subcode, 189 | maxTry: maxTry, 190 | curTry: curTry, 191 | } 192 | 193 | this.emit('loginResponse', emitResp); 194 | 195 | } else if (subcode == 2) { 196 | // Account banned 197 | if(packet.readByte() == 1) { 198 | reason = readString(true); 199 | date = packet.readDWord() + '-' + packet.readDWord() + '-' + packet.readDWord() + ' ' + packet.readDWord() + ':' + packet.readDWord(); 200 | } 201 | 202 | emitResp = { 203 | code: code, 204 | subcode: subcode, 205 | reason: reason, 206 | date: date, 207 | } 208 | 209 | this.emit('loginResponse', emitResp); 210 | 211 | } else if (subcode == 3) { 212 | //User already connected 213 | emitResp = { 214 | code: code, 215 | subcode: subcode, 216 | } 217 | 218 | this.emit('loginResponse', emitResp); 219 | } else if (subcode == 5) { 220 | // Server is full 221 | 222 | emitResp = { 223 | code: code, 224 | subcode: subcode, 225 | } 226 | 227 | this.emit('loginResponse', emitResp); 228 | } else { 229 | // Unknown login error code 230 | emitResp = { 231 | code: code, 232 | subcode: subcode, 233 | } 234 | 235 | this.emit('loginResponse', emitResp); 236 | } 237 | 238 | //Notify game client 239 | this._bot.ServerPacketManager.forwardPacketAll(packet); 240 | } 241 | 242 | } 243 | 244 | function Login$gameLoginResponse(packet) { 245 | var code, subcode, emitResp; 246 | 247 | code = packet.readByte(); 248 | 249 | if(code == 1){ 250 | //Successfully logged in 251 | emitResp = { 252 | code: code, 253 | } 254 | 255 | this.emit('gameLoginResponse', emitResp); 256 | 257 | } else { 258 | // Meh. 259 | subcode = packet.readByte(); 260 | 261 | emitResp = { 262 | code: code, 263 | subcode: subcode, 264 | } 265 | 266 | this.emit('gameLoginResponse', emitResp); 267 | } 268 | } -------------------------------------------------------------------------------- /logic/client/character/CharData.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | var EventEmitter = require('events').EventEmitter; 3 | var PacketWriter = require('../../../packet/PacketWriter'); 4 | var functions = require('../../../functions'); 5 | 6 | module.exports = { 7 | CharData: CharData 8 | }; 9 | 10 | util.inherits(CharData, EventEmitter); 11 | 12 | var $CharData = CharData.prototype; 13 | $CharData.begin = CharData$begin; 14 | $CharData.data = CharData$data; 15 | $CharData.end = CharData$end; 16 | $CharData.id = CharData$id; 17 | $CharData.parse = CharData$parse; 18 | $CharData.confirmSpawn = CharData$confirmSpawn; 19 | 20 | function CharData(bot) { 21 | EventEmitter.call(this); 22 | 23 | this._bot = bot; 24 | 25 | this.charDataBeginPacket = null; 26 | this.charDataPacket = null; 27 | this.charDataEndPacket = null; 28 | this.charDataIdPacket = null; 29 | 30 | this.character = { 31 | skipId: [], 32 | 33 | uniqueId: null, 34 | accountId: null, 35 | race: null, 36 | level: null, 37 | maxLevel: null, 38 | exp: null, 39 | maxExp: null, 40 | gold: null, 41 | skillPoints: null, 42 | statPoints: null, 43 | zerk: null, 44 | 45 | currentHP: null, 46 | currentMP: null, 47 | maxHP: null, 48 | maxMP: null, 49 | 50 | items: new Object(), 51 | avatars: new Object(), 52 | skills: new Object(), 53 | 54 | speed: null, 55 | name: null, 56 | alias: null, 57 | 58 | x: null, 59 | y: null, 60 | inCave: null, 61 | moving: null, 62 | } 63 | 64 | this.firstTime = true; 65 | } 66 | 67 | function CharData$begin(packet) { 68 | this.charDataBeginPacket = packet; 69 | } 70 | 71 | function CharData$data(packet) { 72 | this.charDataPacket = packet; 73 | } 74 | 75 | function CharData$end(packet) { 76 | this.charDataEndPacket = packet; 77 | } 78 | 79 | function CharData$id(packet) { 80 | this.charDataIdPacket = packet; 81 | 82 | this.character.skipId[0] = packet.readByte(); 83 | this.character.skipId[1] = packet.readByte(); 84 | this.character.skipId[2] = packet.readByte(); 85 | this.character.skipId[3] = packet.readByte(); 86 | this.parse(); 87 | 88 | //Check if someone is waiting for chardata and stuff to load into game because we have it already in bot client 89 | this._bot.serverLogic.checkForClientsInCharSelection(); 90 | } 91 | 92 | function CharData$parse() { 93 | var model, itemCount, slot; 94 | 95 | //try { 96 | 97 | //Main 98 | this.charDataPacket.readDWord(); 99 | model = this.charDataPacket.readDWord(); //model 100 | if(model >= 1703 && model <= 1932){ 101 | this.character.race = "CH"; 102 | } else { 103 | this.character.race = "EU"; 104 | } 105 | 106 | this.charDataPacket.readByte(); // volume and height 107 | this.character.level = this.charDataPacket.readByte(); 108 | this.character.maxLevel = this.charDataPacket.readByte(); 109 | this.character.exp = this.charDataPacket.readQWord(); 110 | this.charDataPacket.readWord(); //SP Bar 111 | this.charDataPacket.readWord(); //Unknown 112 | this.character.gold = this.charDataPacket.readQWord(); 113 | this.character.skillPoints = this.charDataPacket.readDWord(); 114 | this.character.statPoints = this.charDataPacket.readWord(); 115 | this.character.zerk = this.charDataPacket.readByte(); 116 | this.charDataPacket.readDWord(); //Unknown 117 | this.character.currentHP = this.charDataPacket.readDWord(); 118 | this.character.currentMP = this.charDataPacket.readDWord(); 119 | this.charDataPacket.readByte(); //Unknown 120 | this.charDataPacket.readByte(); //Unknown 121 | this.charDataPacket.readQWord(); //Unknown 122 | 123 | //Items 124 | this.charDataPacket.readByte(); //max inventory slots 125 | itemCount = this.charDataPacket.readByte(); 126 | for (var i = 0; i < itemCount; i++) { 127 | slot = this.charDataPacket.readByte(); 128 | this.character.items[slot] = this._bot.inventoryParser.parse(); 129 | }; 130 | 131 | //Avatars 132 | this.charDataPacket.readByte(); // max avatars 133 | var avaCount; 134 | avaCount = this.charDataPacket.readByte(); 135 | for (var i = 0; i < avaCount; i++) { 136 | var avaSlot, avaId, ava, avaType, avaPlus, avaBlueAmount; 137 | 138 | avaSlot = this.charDataPacket.readByte(); 139 | this.charDataPacket.readDWord(); 140 | avaId = this.charDataPacket.readDWord(); 141 | 142 | ava = this._bot.gameData.items[avaId]; 143 | avaType = ava.type || undefined; 144 | avaPlus = this.charDataPacket.readByte(); 145 | this.charDataPacket.readQWord(); 146 | this.charDataPacket.readDWord(); 147 | avaBlueAmount = this.charDataPacket.readByte(); 148 | for (var j = 0; j < avaBlueAmount; j++) { 149 | this.charDataPacket.readDWord(); 150 | this.charDataPacket.readDWord(); 151 | }; 152 | this.charDataPacket.readWord(); 153 | this.charDataPacket.readWord(); 154 | 155 | this.character.avatars[avaSlot] = { 156 | model: avaId, 157 | type: avaType, 158 | name: ava.name || undefined, 159 | plus: avaPlus, 160 | 161 | } 162 | 163 | }; 164 | 165 | this.charDataPacket.readByte(); //unknown 166 | 167 | //Mastery 168 | var masteryFlag; 169 | masteryFlag = this.charDataPacket.readByte(); //mastery start 170 | while(masteryFlag == 1) { 171 | this.charDataPacket.readDWord(); //Mastery ID 172 | this.charDataPacket.readByte(); //Master Lv 173 | masteryFlag = this.charDataPacket.readByte(); //new mastery start/end 174 | }; 175 | 176 | this.charDataPacket.readByte(); //unknown 177 | 178 | //Skills 179 | var skillFlag; 180 | skillFlag = this.charDataPacket.readByte(); //skill start 181 | while(skillFlag == 1) { 182 | var skillId, skill; 183 | skillId = this.charDataPacket.readDWord(); //Skill ID 184 | 185 | skill = this._bot.gameData.skills[skillId]; 186 | 187 | this.charDataPacket.readByte(); 188 | skillFlag = this.charDataPacket.readByte(); ///new skill start/end 189 | 190 | this.character.skills[skillId] = skill; 191 | 192 | }; 193 | 194 | //Skip quests 195 | var temp; 196 | temp = []; 197 | while(true) { 198 | temp[0] = temp[1]; 199 | temp[1] = temp[2]; 200 | temp[2] = temp[3]; 201 | temp[3] = this.charDataPacket.readByte(); 202 | if((temp[0] == this.character.skipId[0]) && (temp[1] == this.character.skipId[1]) && (temp[2] == this.character.skipId[2]) && (temp[3] == this.character.skipId[3])) { 203 | this.charDataPacket.pointer -= 4; 204 | break; 205 | } 206 | } 207 | 208 | //Unique ID 209 | this.character.uniqueId = this.charDataPacket.readDWord(); 210 | 211 | //Coordinates 212 | var xSector, ySector, xOffset, zOffset, yOffset; 213 | xSector = this.charDataPacket.readByte(); 214 | ySector = this.charDataPacket.readByte(); 215 | if(ySector == 0x80) { 216 | this.character.inCave = true; 217 | } else { 218 | this.character.inCave = false; 219 | } 220 | 221 | xOffset = this.charDataPacket.readFloat(); 222 | zOffset = this.charDataPacket.readFloat(); 223 | yOffset = this.charDataPacket.readFloat(); 224 | 225 | this.character.x = functions.calculateX(xSector, xOffset); 226 | this.character.y = functions.calculateY(ySector, yOffset); 227 | 228 | this.charDataPacket.readWord(); //position 229 | this.character.moving = this.charDataPacket.readByte(); 230 | this.charDataPacket.readByte(); // Running 231 | this.charDataPacket.readByte(); 232 | this.charDataPacket.readWord(); 233 | 234 | // 235 | this.charDataPacket.readByte(); 236 | this.charDataPacket.readByte(); 237 | this.charDataPacket.readByte(); //Deathflag 238 | this.charDataPacket.readByte(); //Movement flag 239 | this.charDataPacket.readByte(); //Berserker flag 240 | 241 | //Speed 242 | this.charDataPacket.readDWord(); //Walking speed 243 | this.character.speed = this.charDataPacket.readFloat(); //Running speed 244 | this.charDataPacket.readDWord(); //Berserker speed 245 | 246 | //Name & Alias 247 | this.character.name = this.charDataPacket.readString(true); //Player name 248 | this.character.alias = this.charDataPacket.readString(true); //Player alias 249 | 250 | 251 | //Job 252 | this.charDataPacket.readByte(); //Job level 253 | this.charDataPacket.readByte(); //Job type 254 | this.charDataPacket.readDWord(); //Trader exp 255 | this.charDataPacket.readDWord(); //Thief exp 256 | this.charDataPacket.readDWord(); //Hunter exp 257 | this.charDataPacket.readByte(); //Trader level 258 | this.charDataPacket.readByte(); //Thief level 259 | this.charDataPacket.readByte(); //Hunter level 260 | 261 | //Something 262 | this.charDataPacket.readByte(); //PK Flag 263 | this.charDataPacket.readWord(); //Unknown 264 | this.charDataPacket.readDWord(); //Unknown 265 | this.charDataPacket.readByte(); //Unknown 266 | 267 | this.character.accountId = this.charDataPacket.readDWord(); //Account ID 268 | 269 | this.confirmSpawn(); 270 | 271 | this.emit('charData', this.character); 272 | 273 | //} catch(error) { 274 | // console.log('CharData parse error occured.', error, this.charDataPacket); 275 | //} 276 | 277 | } 278 | 279 | function CharData$confirmSpawn() { 280 | if(this._bot.globals.firstSpawnAccepted) { 281 | this._bot.client.send(this._bot.opcodes.CLIENT.CONFIRM_SPAWN, new PacketWriter(), false); 282 | } else { 283 | this._bot.globals.firstSpawnAccepted = true; 284 | } 285 | } -------------------------------------------------------------------------------- /logic/server/ServerLogic.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | var PacketWriter = require('../../packet/PacketWriter'); 3 | var functions = require('../../functions'); 4 | 5 | module.exports = { 6 | ServerLogic: ServerLogic 7 | }; 8 | 9 | var $ServerLogic = ServerLogic.prototype; 10 | $ServerLogic.identify = ServerLogic$identify; 11 | $ServerLogic.patchRequest = ServerLogic$patchRequest; 12 | $ServerLogic.sendPatchInfo = ServerLogic$sendPatchInfo; 13 | $ServerLogic.serverListRequest = ServerLogic$serverListRequest; 14 | $ServerLogic.login = ServerLogic$login; 15 | $ServerLogic.sendHardcodedLoginSuccessPacket = ServerLogic$sendHardcodedLoginSuccessPacket; 16 | $ServerLogic.gameLogin = ServerLogic$gameLogin; 17 | $ServerLogic.characterList = ServerLogic$characterList; 18 | $ServerLogic.characterSelect = ServerLogic$characterSelect; 19 | $ServerLogic.checkForClientsInCharSelection = ServerLogic$checkForClientsInCharSelection; 20 | $ServerLogic.sendCharDataAndStuff = ServerLogic$sendCharDataAndStuff; 21 | $ServerLogic.spawnConfirmation = ServerLogic$spawnConfirmation; 22 | $ServerLogic.sendSuccessByte = ServerLogic$sendSuccessByte; 23 | $ServerLogic.weatherRequest = ServerLogic$weatherRequest; 24 | $ServerLogic.sendSpawns = ServerLogic$sendSpawns; 25 | 26 | 27 | function ServerLogic(bot) { 28 | this._bot = bot; 29 | } 30 | 31 | function ServerLogic$identify(packet, client) { 32 | 33 | //Start client if null 34 | if(!this._bot.client) { 35 | this._bot.createClient(); 36 | } 37 | 38 | //If client state is lower than 50, means client is not connected to game server yet 39 | if(this._bot.globals.clientState.id < 50) { 40 | var resp = new PacketWriter(); 41 | resp.writeString(this._bot.enums.serverType.GATEWAY_SERVER); 42 | resp.writeByte(0); 43 | this._bot.server.send(client, this._bot.opcodes.SERVER.AGENT_SERVER, resp, false); 44 | } else { 45 | var resp = new PacketWriter(); 46 | resp.writeString(this._bot.enums.serverType.AGENT_SERVER); 47 | resp.writeByte(0); 48 | this._bot.server.send(client, this._bot.opcodes.SERVER.AGENT_SERVER, resp, false); 49 | } 50 | 51 | client.state = this._bot.enums.clientState.IDENTIFIED; 52 | } 53 | 54 | function ServerLogic$patchRequest(packet, client) { 55 | this.sendPatchInfo(client); 56 | } 57 | 58 | function ServerLogic$sendPatchInfo(client) { 59 | var resp = new PacketWriter(); 60 | resp.writeDWord(0x05000101); 61 | resp.writeByte(0x20); 62 | this._bot.server.send(client, this._bot.opcodes.SERVER.PATCH_INFO, resp, false); 63 | var resp = new PacketWriter(); 64 | resp.writeDWord(0x01000100); 65 | resp.writeDWord(0x00050A08); 66 | resp.writeWord(0x0000); 67 | resp.writeByte(0x20); 68 | this._bot.server.send(client, this._bot.opcodes.SERVER.PATCH_INFO, resp, false); 69 | var resp = new PacketWriter(); 70 | resp.writeDWord(0x05000101); 71 | resp.writeByte(0x60); 72 | this._bot.server.send(client, this._bot.opcodes.SERVER.PATCH_INFO, resp, false); 73 | var resp = new PacketWriter(); 74 | resp.writeDWord(0x02000300); 75 | resp.writeByte(0x20); 76 | this._bot.server.send(client, this._bot.opcodes.SERVER.PATCH_INFO, resp, false); 77 | var resp = new PacketWriter(); 78 | resp.writeDWord(0x00000101); 79 | resp.writeByte(0xA1); 80 | this._bot.server.send(client, this._bot.opcodes.SERVER.PATCH_INFO, resp, false); 81 | var resp = new PacketWriter(); 82 | resp.writeWord(0x0100); 83 | this._bot.server.send(client, this._bot.opcodes.SERVER.PATCH_INFO, resp, false); 84 | } 85 | 86 | function ServerLogic$serverListRequest(packet, client) { 87 | //Send server list if client already have it 88 | if(this._bot.login.serverListPacket) { 89 | var tmpBuffer, resp; 90 | //Set pointer to beginning 91 | this._bot.login.serverListPacket.pointer = 6; 92 | tmpBuffer = this._bot.login.serverListPacket.readByteArray(this._bot.login.serverListPacket.size); 93 | resp = new PacketWriter(tmpBuffer); 94 | this._bot.server.send(client, this._bot.opcodes.SERVER.SERVER_LIST, resp, false); 95 | } 96 | 97 | client.state = this._bot.enums.clientState.WAITING_LOGIN; 98 | } 99 | 100 | function ServerLogic$login(packet, client) { 101 | //Take username/password and forward packet to server 102 | if(this._bot.globals.clientState == this._bot.enums.clientState.WAITING_LOGIN) { 103 | var tmpBuffer, p, username, password, serverId; 104 | 105 | packet.readByte(); //locale 106 | username = packet.readString(true); 107 | password = packet.readString(true); 108 | serverId = packet.readWord(); 109 | 110 | this._bot.login.sendLogin(username, password, serverId); 111 | } 112 | } 113 | 114 | function ServerLogic$sendHardcodedLoginSuccessPacket() { 115 | var host, port, p; 116 | 117 | host = '127.0.0.1'; //hardcoded for so far :( 118 | port = this._bot.server.listener.address().port; 119 | 120 | if(host && port) { 121 | p = new PacketWriter(); 122 | p.writeByte(0x01); //Success byte 123 | p.writeDWord(0x01); //SessionId. Can be any number since we don't need it. 124 | p.writeString(host); 125 | p.writeWord(port); 126 | this._bot.server.sendAll(this._bot.opcodes.SERVER.LOGIN_REPLY, p, false); 127 | } 128 | } 129 | 130 | function ServerLogic$gameLogin(packet, client) { 131 | this.sendPatchInfo(client); 132 | var resp = new PacketWriter(); 133 | resp.writeByte(0x01); 134 | this._bot.server.send(client, this._bot.opcodes.SERVER.GAME_LOGIN_REPLY, resp, false); 135 | } 136 | 137 | function ServerLogic$characterList(packet, client) { 138 | var tmpBuffer, p; 139 | //Send character list if bot already have it 140 | if(this._bot.charList.charListPacket) { 141 | //Set pointer to beginning 142 | this._bot.charList.charListPacket.pointer = 6; 143 | tmpBuffer = this._bot.charList.charListPacket.readByteArray(this._bot.charList.charListPacket.size); 144 | p = new PacketWriter(tmpBuffer); 145 | this._bot.server.send(client, this._bot.opcodes.SERVER.CHARACTER_LIST, p, false); 146 | } 147 | 148 | //Send char select success and chardata if bot is already in game world 149 | if(this._bot.globals.clientState == this._bot.enums.clientState.IN_GAME) { 150 | this.sendCharDataAndStuff(client); 151 | } 152 | 153 | client.state = this._bot.enums.clientState.WAITING_CHAR_SELECTION; 154 | } 155 | 156 | function ServerLogic$characterSelect(packet, client) { 157 | var charName; 158 | charName = packet.readString(true); 159 | this._bot.charList.selectCharacter(charName); 160 | } 161 | 162 | function ServerLogic$checkForClientsInCharSelection() { 163 | var clients; 164 | clients = this._bot.server.clients; 165 | for(var key in clients) { 166 | var client; 167 | client = clients[key]; 168 | if(client.state == this._bot.enums.clientState.WAITING_CHAR_SELECTION) { 169 | this.sendCharDataAndStuff(client); 170 | } 171 | } 172 | } 173 | 174 | function ServerLogic$sendCharDataAndStuff(client) { 175 | //set client state to loading into game, so proxy will hold incoming game world packets meanwhile 176 | client.state = this._bot.enums.clientState.LOADING_GAME_WORLD; 177 | 178 | this.sendSuccessByte(client); 179 | 180 | this._bot.serverPacketManager.forwardPacket(client, this._bot.charData.charDataBeginPacket, true); 181 | this._bot.serverPacketManager.forwardPacket(client, this._bot.charData.charDataPacket, true); 182 | this._bot.serverPacketManager.forwardPacket(client, this._bot.charData.charDataEndPacket, true); 183 | this._bot.serverPacketManager.forwardPacket(client, this._bot.charData.charDataIdPacket, true); 184 | 185 | this._bot.serverSpawns.sendSpawns(client); 186 | } 187 | 188 | function ServerLogic$spawnConfirmation(packet, client) { 189 | client.state = this._bot.enums.clientState.IN_GAME; 190 | 191 | //send packets which were on hold while loading into game world 192 | for (var i = 0; i < client.packetHoldList.length; i++) { 193 | var packet = client.packetHoldList[i]; 194 | //console.log(packet.opcode.toString('16')); 195 | this._bot.serverPacketManager.forwardPacket(client, packet, true); 196 | } 197 | //remove sent packets 198 | client.packetHoldList.splice(0, client.packetHoldList.length); 199 | } 200 | 201 | function ServerLogic$sendSuccessByte(client) { 202 | p = new PacketWriter(); 203 | p.writeByte(0x01); //success byte 204 | this._bot.server.send(client, this._bot.opcodes.SERVER.CHARACTER_SELECT, p, false); 205 | } 206 | 207 | function ServerLogic$weatherRequest(packet, client) { 208 | this._bot.serverPacketManager.forwardPacket(client, this._bot.world.weatherPacket, true); 209 | client.state = this._bot.enums.clientState.IN_GAME; 210 | } 211 | 212 | function ServerLogic$sendSpawns(client) { 213 | var NPCs, count, pBegin, pData, Pend; 214 | 215 | NPCs = this._bot.spawnManager.NPCs; 216 | count = Object.keys(NPCs).length; 217 | 218 | // Stop this function if there's no spawned objects 219 | if(!count) { 220 | return; 221 | } 222 | 223 | pBegin = new PacketWriter(); 224 | pBegin.writeByte(1); //Spawn action. 225 | pBegin.writeWord(count); 226 | 227 | pData = new PacketWriter(); 228 | 229 | for (var uniqueId in NPCs) { 230 | var NPC; 231 | 232 | NPC = NPCs[uniqueId]; 233 | 234 | pData.writeDWord(NPC.model); 235 | pData.writeDWord(NPC.uniqueId); 236 | pData.writeByte(NPC.xSector); 237 | pData.writeByte(NPC.ySector); 238 | pData.writeFloat(NPC.xOffset); 239 | pData.writeFloat(NPC.zOffset); 240 | pData.writeFloat(NPC.yOffset); 241 | pData.writeWord(NPC.position); 242 | pData.writeByte(NPC.moving); 243 | pData.writeByte(NPC.running); 244 | if(NPC.moving == 1) { 245 | pData.writeByte(NPC.movingData.xSector); 246 | pData.writeByte(NPC.movingData.ySector); 247 | 248 | if(NPC.movingData.ySector == 0x80) { 249 | pData.writeWord(NPC.movingData.xOffset); 250 | pData.writeWord(NPC.movingData.xOffset2); 251 | 252 | pData.writeWord(NPC.movingData.zOffset); 253 | pData.writeWord(NPC.movingData.zOffset2); 254 | 255 | pData.writeWord(NPC.movingData.yOffset); 256 | pData.writeWord(NPC.movingData.yOffset2); 257 | } else { 258 | pData.writeWord(NPC.movingData.xOffset); 259 | pData.writeWord(NPC.movingData.zOffset); 260 | pData.writeWord(NPC.movingData.yOffset); 261 | } 262 | } else { 263 | pData.writeByte(NPC.movingData.noDestination); 264 | pData.writeWord(NPC.movingData.angle); 265 | } 266 | 267 | pData.writeByte(NPC.alive); 268 | pData.writeByte(NPC.unknown1); 269 | pData.writeByte(NPC.unknown2); 270 | pData.writeByte(NPC.unknown3); 271 | pData.writeDWord(NPC.walkingSpeed); 272 | pData.writeDWord(NPC.runningSpeed); 273 | pData.writeDWord(NPC.berserkerSpeed); 274 | pData.writeByte(NPC.unknown4); 275 | pData.writeByte(NPC.check); 276 | 277 | if(NPC.check != 0) { 278 | pData.writeByte(NPC.count); 279 | for (var i = 0; i < NPC.count; i++) { 280 | pData.writeByte(NPC.unknown5[i]); 281 | }; 282 | } 283 | 284 | 285 | 286 | }; 287 | 288 | pEnd = new PacketWriter(); 289 | 290 | console.log('Sending NPC spawn'); 291 | //console.log(pData); 292 | 293 | this._bot.server.send(client, this._bot.opcodes.SERVER.GROUPSPAWN_BEGIN, pBegin, false); 294 | this._bot.server.send(client, this._bot.opcodes.SERVER.GROUPSPAWN_DATA, pData, false); 295 | this._bot.server.send(client, this._bot.opcodes.SERVER.GROUPSPAWN_END, pEnd, false); 296 | 297 | } -------------------------------------------------------------------------------- /Bot.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | var EventEmitter = require('events').EventEmitter; 3 | var hexy = require('hexy').hexy; 4 | var PacketWriter = require('./packet/PacketWriter'); 5 | var settings = require('./vars/settings'); 6 | var globals = require('./vars/globals'); 7 | var enums = require('./vars/enums'); 8 | var opcodes = require('./vars/opcodes'); 9 | var Client = require('./connections/Client'); 10 | var Server = require('./connections/Server'); 11 | var ClientPacketManager = require('./logic/client/packet/ClientPacketManager').ClientPacketManager; 12 | var ServerPacketManager = require('./logic/server/packet/ServerPacketManager').ServerPacketManager; 13 | //Client 14 | var GameData = require('./gamedata/GameData').GameData; 15 | var Login = require('./logic/client/login/Login').Login; 16 | var Ping = require('./logic/client/ping/Ping').Ping; 17 | var CharList = require('./logic/client/character/CharList').CharList; 18 | var CharData = require('./logic/client/character/CharData').CharData; 19 | var InventoryParser = require('./logic/client/items/InventoryParser').InventoryParser; 20 | var World = require('./logic/client/world/World').World; 21 | var Teleport = require('./logic/client/teleport/Teleport').Teleport; 22 | var GroupSpawn = require('./logic/client/spawns/GroupSpawn').GroupSpawn; 23 | var SpawnManager = require('./logic/client/spawns/SpawnManager').SpawnManager; 24 | var SpawnParser = require('./logic/client/spawns/SpawnParser').SpawnParser; 25 | //Server 26 | var ServerLogic = require('./logic/server/ServerLogic').ServerLogic; 27 | var ServerSpawns = require('./logic/server/ServerSpawns').ServerSpawns; 28 | 29 | module.exports = { 30 | create: create, 31 | Bot: Bot 32 | }; 33 | 34 | function create(options) { 35 | return new Bot(options); 36 | } 37 | 38 | util.inherits(Bot, EventEmitter); 39 | 40 | var $Bot = Bot.prototype; 41 | $Bot.createClient = Bot$createClient; 42 | $Bot.createServer = Bot$createServer; 43 | $Bot.start = Bot$start; 44 | $Bot.sendLogin = Bot$sendLogin; 45 | $Bot.selectCharacter = Bot$selectCharacter; 46 | 47 | function Bot(options) { 48 | EventEmitter.call(this); 49 | 50 | options = this.options = { 51 | host: options && options.host, 52 | port: options && options.port || 15779, 53 | locale: options && options.locale || 22, 54 | version: options && options.version || 188, 55 | }; 56 | 57 | // vars 58 | this.settings = settings; 59 | this.globals = globals; 60 | this.enums = enums; 61 | this.opcodes = opcodes; 62 | 63 | // Store options to settings 64 | this.settings.host = options.host; 65 | this.settings.port = options.port; 66 | this.settings.locale = options.locale; 67 | this.settings.version = options.version; 68 | 69 | this.client = null; 70 | this.server = null; 71 | this.gatewayServer = null; 72 | this.agentServer = null; 73 | 74 | this._bound = { 75 | //Client 76 | onClientError: onClientError.bind(this), 77 | onClientClose: onClientClose.bind(this), 78 | onClientPacket: onClientPacket.bind(this), 79 | //Server 80 | onServerListening: onServerListening.bind(this), 81 | onServerConnection: onServerConnection.bind(this), 82 | onServerPacket: onServerPacket.bind(this), 83 | //Login 84 | onIdentified: onIdentified.bind(this), 85 | onServerList: onServerList.bind(this), 86 | onLoginError: onLoginError.bind(this), 87 | onLoginResponse: onLoginResponse.bind(this), 88 | onGameLoginResponse: onGameLoginResponse.bind(this), 89 | //CharList 90 | onCharList: onCharList.bind(this), 91 | onCharListError: onCharListError.bind(this), 92 | oncharacterSelected: oncharacterSelected.bind(this), 93 | //CharData 94 | onCharData: onCharData.bind(this), 95 | //Teleport 96 | onTeleportRequest: onTeleportRequest.bind(this), 97 | }; 98 | 99 | 100 | 101 | //ClientPacketManager 102 | this.clientPacketManager = new ClientPacketManager(this); 103 | 104 | //ServerPacketManager 105 | this.serverPacketManager = new ServerPacketManager(this); 106 | 107 | //GameData 108 | this.gameData = new GameData(); 109 | 110 | //Login 111 | this.login = new Login(this); 112 | this.login.on('identified', this._bound.onIdentified); 113 | this.login.on('serverList', this._bound.onServerList); 114 | this.login.on('loginError', this._bound.onLoginError); 115 | this.login.on('loginResponse', this._bound.onLoginResponse); 116 | this.login.on('gameLoginResponse', this._bound.onGameLoginResponse); 117 | 118 | //Ping 119 | this.ping = new Ping(this); 120 | 121 | //CharList 122 | this.charList = new CharList(this); 123 | this.charList.on('charList', this._bound.onCharList); 124 | this.charList.on('charListError', this._bound.onCharListError); 125 | this.charList.on('characterSelected', this._bound.oncharacterSelected); 126 | 127 | //CharData 128 | this.charData = new CharData(this); 129 | this.charData.on('charData', this._bound.onCharData); 130 | 131 | //InventoryParser 132 | this.inventoryParser = new InventoryParser(this); 133 | 134 | //World 135 | this.world = new World(this); 136 | 137 | //Teleport 138 | this.teleport = new Teleport(this); 139 | this.teleport.on('teleportRequest', this._bound.onTeleportRequest); 140 | 141 | //GroupSpawn 142 | this.groupSpawn = new GroupSpawn(this); 143 | 144 | //SpawnManager 145 | this.spawnManager = new SpawnManager(this); 146 | 147 | //SpawnParser 148 | this.spawnParser = new SpawnParser(this); 149 | 150 | //===Server modules=== 151 | 152 | //ServerLogic 153 | this.serverLogic = new ServerLogic(this); 154 | 155 | //ServerSpawns 156 | this.serverSpawns = new ServerSpawns(this); 157 | 158 | } 159 | 160 | function Bot$createClient(){ 161 | var client, bound; 162 | 163 | bound = this._bound; 164 | 165 | client = this.client = Client.connect({ port: this.options.port, host: this.options.host }); 166 | client.on('error', bound.onClientError); 167 | client.on('close', bound.onClientClose); 168 | client.on('packet', bound.onClientPacket); 169 | 170 | } 171 | 172 | function Bot$createServer(){ 173 | var server; 174 | bound = this._bound; 175 | 176 | server = this.server = Server.listen(this); 177 | server.on('listening', bound.onServerListening); 178 | server.on('connection', bound.onServerConnection); 179 | server.on('packet', bound.onServerPacket); 180 | 181 | } 182 | 183 | // Triggers _createClient() which start connection with the game server 184 | function Bot$start(){ 185 | if(this.client == null){ 186 | this.createServer(); 187 | this.createClient(); 188 | 189 | } 190 | } 191 | 192 | function Bot$sendLogin(username, password, serverId){ 193 | this.login.sendLogin(username, password, serverId); 194 | } 195 | 196 | function Bot$selectCharacter(charName){ 197 | this.charList.selectCharacter(charName); 198 | } 199 | 200 | // Event handlers 201 | 202 | //Client events 203 | function onClientPacket(packet) { 204 | switch (packet.opcode) { 205 | case this.opcodes.SERVER.AGENT_SERVER: 206 | this.login.identify(packet); 207 | break; 208 | case this.opcodes.SERVER.SERVER_LIST: 209 | this.login.serverList(packet); 210 | break; 211 | case this.opcodes.SERVER.CAPTCHA_REQUEST: 212 | this.login.captchaRequest(packet); 213 | break; 214 | case this.opcodes.SERVER.LOGIN_REPLY: 215 | this.login.loginResponse(packet); 216 | break; 217 | case this.opcodes.SERVER.GAME_LOGIN_REPLY: 218 | this.login.gameLoginResponse(packet); 219 | break; 220 | case this.opcodes.SERVER.CHARACTER_LIST: 221 | this.charList.analyze(packet); 222 | break; 223 | case this.opcodes.SERVER.CHARACTER_SELECT: 224 | this.charList.characterSelected(packet); 225 | break; 226 | case this.opcodes.SERVER.TELEPORT_REQUEST: 227 | this.teleport.teleportRequest(packet); 228 | break; 229 | case this.opcodes.SERVER.CHARDATA_BEGIN: 230 | this.charData.begin(packet); 231 | break; 232 | case this.opcodes.SERVER.CHARDATA_DATA: 233 | this.charData.data(packet); 234 | break; 235 | case this.opcodes.SERVER.CHARDATA_END: 236 | this.charData.end(packet); 237 | break; 238 | case this.opcodes.SERVER.CHARDATA_ID: 239 | this.charData.id(packet); 240 | break; 241 | case this.opcodes.SERVER.WEATHER: 242 | this.world.weather(packet); 243 | break; 244 | case this.opcodes.SERVER.SINGLE_SPAWN: 245 | this.spawnManager.spawn(packet); 246 | break; 247 | case this.opcodes.SERVER.SINGLE_DESPAWN: 248 | this.spawnManager.despawn(packet); 249 | break; 250 | case this.opcodes.SERVER.GROUPSPAWN_BEGIN: 251 | this.groupSpawn.groupSpawnBegin(packet); 252 | break; 253 | case this.opcodes.SERVER.GROUPSPAWN_DATA: 254 | this.groupSpawn.groupSpawnData(packet); 255 | break; 256 | case this.opcodes.SERVER.GROUPSPAWN_END: 257 | this.groupSpawn.groupSpawnEnd(packet); 258 | break; 259 | default: 260 | break; 261 | } 262 | 263 | //Forward packet to connected clients on the local server 264 | this.serverPacketManager.forwardPacketAll(packet); 265 | 266 | this.emit('clientPacket', packet); 267 | } 268 | 269 | function onClientError(error) { 270 | this.emit('clientError', error); 271 | } 272 | 273 | function onClientClose(hadError) { 274 | //Stop ping timer 275 | this.ping.stop(); 276 | globals.clientState = enums.clientState.OFFLINE; 277 | 278 | this.emit('clientClose', hadError); 279 | } 280 | 281 | function onIdentified(server){ 282 | //Change client state 283 | this.globals.clientState = this.enums.clientState.IDENTIFIED; 284 | //Stop ping timer 285 | this.ping.start(); 286 | 287 | this.emit('identified', server); 288 | } 289 | 290 | function onServerList(serverList) { 291 | // Change client state to WAITING_LOGIN 292 | this.globals.clientState = this.enums.clientState.WAITING_LOGIN; 293 | // Make auto login if needed 294 | this.login.autoLogin(); 295 | 296 | this.emit('serverList', serverList); 297 | } 298 | 299 | function onLoginError(error) { 300 | this.emit('loginError', error); 301 | } 302 | 303 | function onLoginResponse(data) { 304 | if(data.code == 1) { 305 | if(this.settings.system.connectToAgentServer) { 306 | this.client.reconnect({port: data.port, host: data.host}); 307 | } 308 | } 309 | 310 | this.emit('loginResponse', data); 311 | } 312 | 313 | function onGameLoginResponse(data) { 314 | //Request character list 315 | if(data.code === 1) { 316 | if(this.settings.system.requestCharList) { 317 | this.charList.requestCharList(); 318 | } 319 | } 320 | 321 | this.emit('gameLoginResponse', data); 322 | } 323 | 324 | function onCharList(charList) { 325 | var charName; 326 | 327 | // Change client state to WAITING_CHAR_SELECTION 328 | this.globals.clientState = this.enums.clientState.WAITING_CHAR_SELECTION; 329 | 330 | charName = this.settings.charName; 331 | //Select character if needed 332 | if(this.settings.autologin && charName){ 333 | this.charList.selectCharacter(charName); 334 | } 335 | 336 | this.emit('charList', charList); 337 | } 338 | 339 | function onCharData(character) { 340 | this.emit('charData', character); 341 | } 342 | 343 | function onCharListError(error) { 344 | this.emit('charListError', error); 345 | } 346 | 347 | function oncharacterSelected() { 348 | // Change client state to IN_GAME 349 | this.globals.clientState = this.enums.clientState.IN_GAME; 350 | 351 | this.emit('characterSelected'); 352 | } 353 | 354 | function onTeleportRequest() { 355 | this.emit('teleportRequest'); 356 | } 357 | 358 | //Server events 359 | function onServerPacket(packet, client) { 360 | switch (packet.opcode) { 361 | case this.opcodes.CLIENT.AGENT_SERVER: 362 | this.serverLogic.identify(packet, client); 363 | break; 364 | case this.opcodes.CLIENT.PATCH_REQUEST: 365 | this.serverLogic.patchRequest(packet, client); 366 | break; 367 | case this.opcodes.CLIENT.REQUEST_SERVER_LIST: 368 | this.serverLogic.serverListRequest(packet, client); 369 | break; 370 | case this.opcodes.CLIENT.LOGIN: 371 | this.serverLogic.login(packet, client); 372 | break; 373 | case this.opcodes.CLIENT.GAME_LOGIN: 374 | this.serverLogic.gameLogin(packet, client); 375 | break; 376 | case this.opcodes.CLIENT.CHARACTER_LIST: 377 | this.serverLogic.characterList(packet, client); 378 | break; 379 | case this.opcodes.CLIENT.CHARACTER_SELECT: 380 | this.serverLogic.characterSelect(packet, client); 381 | break; 382 | case this.opcodes.CLIENT.CONFIRM_SPAWN: 383 | this.serverLogic.spawnConfirmation(packet, client); 384 | break; 385 | case this.opcodes.CLIENT.WEATHER_REQUEST: 386 | this.serverLogic.weatherRequest(packet, client); 387 | break; 388 | } 389 | 390 | //Forward packet to remote game server 391 | this.clientPacketManager.forwardPacket(packet, client); 392 | this.emit('serverPacket', packet, client); 393 | } 394 | 395 | function onServerListening(port) { 396 | this.emit('serverListening', port); 397 | } 398 | 399 | function onServerConnection(socket) { 400 | this.emit('serverConnection', socket); 401 | } -------------------------------------------------------------------------------- /logic/client/spawns/SpawnParser.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | var PacketWriter = require('../../../packet/PacketWriter'); 3 | var functions = require('../../../functions'); 4 | 5 | module.exports = { 6 | SpawnParser: SpawnParser 7 | }; 8 | 9 | var $SpawnParser = SpawnParser.prototype; 10 | $SpawnParser.parseChar = SpawnParser$parseChar; 11 | $SpawnParser.parseGate = SpawnParser$parseGate; 12 | $SpawnParser.parsePet = SpawnParser$parsePet; 13 | $SpawnParser.parseNPC = SpawnParser$parseNPC; 14 | $SpawnParser.parseMonster = SpawnParser$parseMonster; 15 | $SpawnParser.parseOther = SpawnParser$parseOther; 16 | $SpawnParser.parseItem = SpawnParser$parseItem; 17 | 18 | function SpawnParser(bot) { 19 | this._bot = bot; 20 | } 21 | 22 | function SpawnParser$parseChar(packet, model) { 23 | var tempObj; 24 | tempObj = new Object(); 25 | 26 | tempObj.model = model; 27 | tempObj.volume = packet.readByte(); 28 | tempObj.rank = packet.readByte(); 29 | tempObj.icons = packet.readByte(); 30 | tempObj.unknown1 = packet.readByte(); 31 | tempObj.maxSlots = packet.readByte(); 32 | 33 | tempObj.trade = 0; 34 | tempObj.itemCount = packet.readByte(); 35 | tempObj.items = new Object(); 36 | for (var i = 0; i < tempObj.itemCount; i++) { 37 | var itemId, item; 38 | itemId = packet.readDWord(); 39 | tempObj.items[itemId] = new Object(); 40 | tempObj.items[itemId].id = itemId; 41 | item = this._bot.gameData.items[itemId]; 42 | if(item.type.startsWith('ITEM_CH') || item.type.startsWith('ITEM_EU') || item.type.startsWith('ITEM_FORT') || item.type.startsWith('ITEM_ROC_CH') || item.type.startsWith('ITEM_ROC_EU')) { 43 | tempObj.items[itemId].plus = packet.readByte(); 44 | } 45 | if(item.type.contains('_TRADE_TRADER_') || item.type.contains('_TRADE_HUNTER_') || item.type.contains('_TRADE_THIEF_') ) { 46 | tempObj.trade = 1; 47 | } 48 | }; 49 | 50 | tempObj.maxAvatarSlots = packet.readByte(); 51 | tempObj.avatarCount = packet.readByte(); 52 | tempObj.avatars = new Object(); 53 | for (var i = 0; i < tempObj.avatarCount; i++) { 54 | var avatarId, avatar; 55 | avatarId = packet.readDWord(); 56 | tempObj.avatars[avatarId] = new Object(); 57 | tempObj.avatars[avatarId].id = avatarId; 58 | tempObj.avatars[avatarId].plus = packet.readByte(); 59 | } 60 | tempObj.mask = packet.readByte(); 61 | tempObj.maskData = new Object(); 62 | if(tempObj.mask == 1) { 63 | var maskId, mask; 64 | maskId = packet.readDWord(); 65 | tempObj.maskData.id = maskId; 66 | mask = this._bot.gameData.chars[maskId]; 67 | if(mask.type.startsWith('CHAR')) { 68 | tempObj.maskData.unknown1 = packet.readByte(); 69 | tempObj.maskData.count = packet.readByte(); 70 | tempObj.maskData.unknownData = []; 71 | for (var i = 0; i < tempObj.maskData.count; i++) { 72 | tempObj.maskData.unknownData.push(packet.readDWord()); 73 | }; 74 | } 75 | 76 | } 77 | 78 | tempObj.uniqueId = packet.readDWord(); 79 | 80 | tempObj.xSector = packet.readByte(); 81 | tempObj.ySector = packet.readByte(); 82 | tempObj.xOffset = packet.readFloat(); 83 | tempObj.zOffset = packet.readFloat(); 84 | tempObj.yOffset = packet.readFloat(); 85 | 86 | tempObj.position = packet.readWord(); 87 | tempObj.moving = packet.readByte(); 88 | tempObj.running = packet.readByte(); 89 | 90 | tempObj.movingData = new Object(); 91 | if(tempObj.moving == 1) { 92 | tempObj.movingData.xSector = packet.readByte(); 93 | tempObj.movingData.ySector = packet.readByte(); 94 | if(tempObj.movingData.ySector == 0x80) { 95 | tempObj.movingData.xOffset = packet.readWord(); 96 | tempObj.movingData.xOffset2 = packet.readWord(); 97 | 98 | tempObj.movingData.zOffset = packet.readWord(); 99 | tempObj.movingData.zOffset2 = packet.readWord(); 100 | 101 | tempObj.movingData.yOffset = packet.readWord(); 102 | tempObj.movingData.yOffset2 = packet.readWord(); 103 | } else { 104 | tempObj.movingData.xOffset = packet.readWord(); 105 | tempObj.movingData.zOffset = packet.readWord(); 106 | tempObj.movingData.yOffset = packet.readWord(); 107 | } 108 | } else { 109 | tempObj.movingData.noDestination = packet.readByte(); 110 | tempObj.movingData.angle = packet.readWord(); 111 | } 112 | 113 | tempObj.unknown2 = packet.readByte(); 114 | tempObj.alive = packet.readByte(); 115 | tempObj.unknown3 = packet.readByte(); 116 | tempObj.unknown4 = packet.readByte(); 117 | //tempObj.unknown5 = packet.readByte(); 118 | 119 | tempObj.walkingSpeed = packet.readDWord(); 120 | tempObj.runningSpeed = packet.readDWord(); 121 | tempObj.berserkerSpeed = packet.readDWord(); 122 | 123 | tempObj.activeSkillsCount = packet.readByte(); 124 | tempObj.activeSkills = new Object(); 125 | 126 | for (var i = 0; i < tempObj.activeSkillsCount; i++) { 127 | var skillId, skill; 128 | skillId = packet.readDWord(); 129 | tempObj.activeSkills[skillId] = new Object(); 130 | tempObj.activeSkills[skillId].id = skillId; 131 | skill = this._bot.gameData.skills[skillId]; 132 | tempObj.activeSkills[skillId].tempId = packet.readDWord(); 133 | if(skill.type.startsWith('SKILL_EU_CLERIC_RECOVERYA_GROUP') || skill.type.startsWith('SKILL_EU_BARD_BATTLAA_GUARD') || skill.type.startsWith('SKILL_EU_BARD_DANCEA') || skill.type.startsWith('SKILL_EU_BARD_SPEEDUPA_HITRATE')) { 134 | tempObj.activeSkills[skillId].unknown1 = packet.readByte(); 135 | } 136 | }; 137 | tempObj.name = packet.readString(true); 138 | if(tempObj.trade == 1) { 139 | tempObj.unknown6 = packet.readQWord(); 140 | tempObj.guildName = packet.readString(true); //Guild name 141 | } else { 142 | tempObj.jobType = packet.readByte(); 143 | tempObj.jobLevel = packet.readByte(); 144 | tempObj.pvpState = packet.readByte(); 145 | tempObj.transport = packet.readByte(); 146 | tempObj.unknown7 = packet.readByte(); 147 | if(tempObj.transport == 1) { 148 | tempObj.transportId = packet.readDWord(); 149 | } 150 | tempObj.unknown8 = packet.readByte(); 151 | tempObj.stallFlag = packet.readByte(); 152 | 153 | tempObj.unknown9 = packet.readByte(); 154 | tempObj.guildName = packet.readString(true); 155 | tempObj.guildId = packet.readDWord(); 156 | tempObj.grantName = packet.readString(true); 157 | tempObj.unknown10 = packet.readDWord(); 158 | tempObj.unknown11 = packet.readDWord(); 159 | tempObj.unknown12 = packet.readDWord(); 160 | tempObj.unknown13 = packet.readWord(); 161 | if(tempObj.stallFlag == 4) { 162 | tempObj.stallName = packet.readString(true); 163 | tempObj.unknown14 = packet.readDWord(); 164 | } 165 | /* 166 | tempObj.unknown8 = packet.readByte(); 167 | tempObj.unknown9 = packet.readByte(); 168 | if(tempObj.unknown9 == 1) { 169 | tempObj.unknown10 = packet.readDWord(); 170 | } 171 | tempObj.jobType = packet.readByte(); 172 | //tempObj.jobLevel = packet.readByte(); //Need more tests. 173 | tempObj.stallFlag = packet.readByte(); 174 | tempObj.guildName = packet.readString(true); 175 | tempObj.guildId = packet.readDWord(); 176 | tempObj.grantName = packet.readString(true); 177 | tempObj.unknown11 = packet.readDWord(); 178 | tempObj.unknown12 = packet.readDWord(); 179 | tempObj.unknown13 = packet.readDWord(); 180 | tempObj.unknown14 = packet.readWord(); 181 | if(tempObj.stallFlag == 4) { 182 | tempObj.stallName = packet.readString(true); 183 | tempObj.unknown15 = packet.readDWord(); 184 | } 185 | */ 186 | 187 | } 188 | tempObj.PKFlag = packet.readWord(); // PK Flag (0xFF); 189 | 190 | this._bot.spawnManager.characters[tempObj.uniqueId] = tempObj; 191 | console.log('================================='); 192 | console.log('Spawn character: ' + tempObj.name); 193 | console.log('Unique ID: ' + tempObj.uniqueId + ' Model: ' + tempObj.model); 194 | console.log('================================='); 195 | } 196 | 197 | function SpawnParser$parseGate(packet, model) { 198 | var tempPortal; 199 | tempObj = new Object(); 200 | 201 | tempObj.model = model; 202 | tempObj.uniqueId = packet.readDWord(); 203 | tempObj.unknown1 = packet.readByte(); 204 | tempObj.unknown2 = packet.readByte(); 205 | tempObj.unknown3 = packet.readFloat(); 206 | tempObj.unknown4 = packet.readFloat(); 207 | tempObj.unknown5 = packet.readFloat(); 208 | tempObj.unknown6 = packet.readWord(); 209 | tempObj.unknown7 = packet.readDWord(); 210 | tempObj.unknown8 = packet.readQWord(); 211 | this._bot.spawnManager.gates[tempObj.uniqueId] = tempObj; 212 | console.log('================================='); 213 | console.log('Spawn portal:' + tempObj.model); 214 | console.log('Unique ID: ' + tempObj.uniqueId + ' Model: ' + tempObj.model); 215 | console.log('================================='); 216 | } 217 | 218 | function SpawnParser$parsePet(packet, model) { 219 | var tempObj, pet, tempType; 220 | tempObj = new Object(); 221 | 222 | tempObj.model = model; 223 | pet = this._bot.gameData.chars[model]; 224 | tempObj.uniqueId = packet.readDWord(); 225 | tempObj.xSector = packet.readByte(); 226 | tempObj.ySector = packet.readByte(); 227 | tempObj.xOffset = packet.readFloat(); 228 | tempObj.zOffset = packet.readFloat(); 229 | tempObj.yOffset = packet.readFloat(); 230 | tempObj.position = packet.readWord(); 231 | tempObj.moving = packet.readByte(); 232 | 233 | tempObj.movingData = new Object(); 234 | if(tempObj.moving == 1) { 235 | tempObj.movingData.xSector = packet.readByte(); 236 | tempObj.movingData.ySector = packet.readByte(); 237 | if(tempObj.movingData.ySector == 0x80) { 238 | tempObj.movingData.xOffset = packet.readWord(); 239 | tempObj.movingData.xOffset2 = packet.readWord(); 240 | 241 | tempObj.movingData.zOffset = packet.readWord(); 242 | tempObj.movingData.zOffset2 = packet.readWord(); 243 | 244 | tempObj.movingData.yOffset = packet.readWord(); 245 | tempObj.movingData.yOffset2 = packet.readWord(); 246 | } else { 247 | tempObj.movingData.xOffset = packet.readWord(); 248 | tempObj.movingData.zOffset = packet.readWord(); 249 | tempObj.movingData.yOffset = packet.readWord(); 250 | } 251 | } else { 252 | tempObj.movingData.noDestination = packet.readByte(); 253 | tempObj.movingData.angle = packet.readWord(); 254 | } 255 | 256 | tempObj.unknown1 = packet.readByte(); 257 | tempObj.unknown2 = packet.readByte(); 258 | tempObj.unknown3 = packet.readByte(); 259 | tempObj.unknown4 = packet.readByte(); 260 | tempObj.unknown5 = packet.readByte(); 261 | tempObj.unknown6 = packet.readFloat(); 262 | tempObj.speed = packet.readFloat(); 263 | tempObj.unknown7 = packet.readFloat(); 264 | tempObj.unknown8 = packet.readWord(); 265 | tempType = pet.type; 266 | if(pet.type.startsWith('COS_P_BEAR') || pet.type.startsWith('COS_P_FOX') || pet.type.startsWith('COS_P_KANGAROO') || pet.type.startsWith('COS_P_PENGUIN') || pet.type.startsWith('COS_P_RAVEN') || pet.type.startsWith('COS_P_JINN') || pet.type.startsWith('COS_P_WOLF') || pet.type.startsWith('COS_P_WOLF_WHITE') || pet.type.startsWith('COS_P_WOLF_WHITE_SMALL')) { 267 | tempType = tempType.substring(0, tempType.length - 4) 268 | } 269 | if(tempType.startsWith('COS_C') || tempType.startsWith('COS_T_DHORSE')) { 270 | //Do nothing 271 | } else if(this._bot.gameData.petTypes.grabPets.indexOf(tempType) != -1) { 272 | tempObj.petName = packet.readString(true); 273 | tempObj.ownerName = packet.readString(true); 274 | tempObj.unknown9 = packet.readByte(); 275 | tempObj.ownerId = packet.readDWord(); 276 | } else if(this._bot.gameData.petTypes.attackPets.indexOf(tempType) != -1) { 277 | tempObj.petName = packet.readString(true); 278 | tempObj.ownerName = packet.readString(true); 279 | tempObj.unknown10 = packet.readByte(); 280 | tempObj.unknown11 = packet.readByte(); 281 | tempObj.ownerId = packet.readDWord(); 282 | try { 283 | var b1, b2, b3, b4; 284 | tempObj.b1 = b1 = packet.readByte(); 285 | tempObj.b2 = b2 = packet.readByte(); 286 | tempObj.b3 = b3 = packet.readByte(); 287 | tempObj.b4 = b4 = packet.readByte(); 288 | 289 | if(b1 == 255 && b2 == 255 && b3 == 255 && b4 == 255) { 290 | tempObj.unknown12 = packet.readWord(); 291 | } else { 292 | packet.pointer -= 4; 293 | } 294 | 295 | }catch (err) {} 296 | 297 | 298 | 299 | } else if(tempType.contains('COS_T')) { 300 | tempObj.ownerName = packet.readString(true); 301 | tempObj.unknown13 = packet.readByte(); 302 | tempObj.unknown14 = packet.readByte(); 303 | tempObj.unknown15 = packet.readDWord(); 304 | tempObj.unknown16 = packet.readByte(); 305 | } else if (tempType.startsWith('TRADE_COS_QUEST_TRADE')) { 306 | tempObj.ownerName = packet.readString(true); 307 | tempObj.unknown17 = packet.readWord(); 308 | tempObj.unknown18 = packet.readDWord(); 309 | } else { 310 | tempObj.ownerName = packet.readString(true); 311 | tempObj.unknown19 = packet.readByte(); 312 | tempObj.unknown20 = packet.readByte(); 313 | tempObj.unknown21 = packet.readDWord(); 314 | } 315 | this._bot.spawnManager.pets[tempObj.uniqueId] = tempObj; 316 | console.log('================================='); 317 | console.log('Spawn pet: ' + pet.type); 318 | console.log('Unique ID: ' + tempObj.uniqueId + ' Model: ' + tempObj.model); 319 | console.log('================================='); 320 | //console.log(tempObj); 321 | } 322 | 323 | function SpawnParser$parseNPC(packet, model) { 324 | var tempObj, NPC; 325 | tempObj = new Object(); 326 | 327 | tempObj.model = model; 328 | NPC = this._bot.gameData.chars[model]; 329 | tempObj.uniqueId = packet.readDWord(); 330 | tempObj.xSector = packet.readByte(); 331 | tempObj.ySector = packet.readByte(); 332 | tempObj.xOffset = packet.readFloat(); 333 | tempObj.zOffset = packet.readFloat(); 334 | tempObj.yOffset = packet.readFloat(); 335 | tempObj.position = packet.readWord(); 336 | tempObj.moving = packet.readByte(); 337 | tempObj.running = packet.readByte(); 338 | 339 | tempObj.movingData = new Object(); 340 | if(tempObj.moving == 1) { 341 | tempObj.movingData.xSector = packet.readByte(); 342 | tempObj.movingData.ySector = packet.readByte(); 343 | if(tempObj.movingData.ySector == 0x80) { 344 | tempObj.movingData.xOffset = packet.readWord(); 345 | tempObj.movingData.xOffset2 = packet.readWord(); 346 | 347 | tempObj.movingData.zOffset = packet.readWord(); 348 | tempObj.movingData.zOffset2 = packet.readWord(); 349 | 350 | tempObj.movingData.yOffset = packet.readWord(); 351 | tempObj.movingData.yOffset2 = packet.readWord(); 352 | } else { 353 | tempObj.movingData.xOffset = packet.readWord(); 354 | tempObj.movingData.zOffset = packet.readWord(); 355 | tempObj.movingData.yOffset = packet.readWord(); 356 | } 357 | } else { 358 | tempObj.movingData.noDestination = packet.readByte(); 359 | tempObj.movingData.angle = packet.readWord(); 360 | } 361 | 362 | tempObj.alive = packet.readByte(); 363 | tempObj.unknown1 = packet.readByte(); 364 | tempObj.unknown2 = packet.readByte(); 365 | tempObj.unknown3 = packet.readByte(); 366 | //tempObj.berserkerActive = packet.readByte(); 367 | tempObj.walkingSpeed = packet.readDWord(); 368 | tempObj.runningSpeed = packet.readDWord(); 369 | tempObj.berserkerSpeed = packet.readDWord(); 370 | 371 | tempObj.unknown4 = packet.readByte(); 372 | 373 | tempObj.check = packet.readByte(); 374 | if(tempObj.check != 0) { 375 | tempObj.count = packet.readByte(); 376 | tempObj.unknown5 = []; 377 | for (var i = 0; i < tempObj.count; i++) { 378 | tempObj.unknown5.push(packet.readByte()); 379 | }; 380 | } 381 | this._bot.spawnManager.NPCs[tempObj.uniqueId] = tempObj; 382 | console.log('================================='); 383 | console.log('Spawn NPC: ' + NPC.type); 384 | console.log('Unique ID: ' + tempObj.uniqueId + ' Model: ' + tempObj.model); 385 | console.log('================================='); 386 | } 387 | 388 | function SpawnParser$parseMonster(packet, model) { 389 | var tempObj, monster; 390 | tempObj = new Object(); 391 | 392 | tempObj.model = model; 393 | monster = this._bot.gameData.chars[model]; 394 | tempObj.uniqueId = packet.readDWord(); 395 | tempObj.xSector = packet.readByte(); 396 | tempObj.ySector = packet.readByte(); 397 | tempObj.xOffset = packet.readFloat(); 398 | tempObj.zOffset = packet.readFloat(); 399 | tempObj.yOffset = packet.readFloat(); 400 | tempObj.position = packet.readWord(); 401 | tempObj.moving = packet.readByte(); 402 | tempObj.running = packet.readByte(); 403 | 404 | tempObj.movingData = new Object(); 405 | if(tempObj.moving == 1) { 406 | tempObj.movingData.xSector = packet.readByte(); 407 | tempObj.movingData.ySector = packet.readByte(); 408 | if(tempObj.movingData.ySector == 0x80) { 409 | tempObj.movingData.xOffset = packet.readWord(); 410 | tempObj.movingData.xOffset2 = packet.readWord(); 411 | 412 | tempObj.movingData.zOffset = packet.readWord(); 413 | tempObj.movingData.zOffset2 = packet.readWord(); 414 | 415 | tempObj.movingData.yOffset = packet.readWord(); 416 | tempObj.movingData.yOffset2 = packet.readWord(); 417 | } else { 418 | tempObj.movingData.xOffset = packet.readWord(); 419 | tempObj.movingData.zOffset = packet.readWord(); 420 | tempObj.movingData.yOffset = packet.readWord(); 421 | } 422 | } else { 423 | tempObj.movingData.noDestination = packet.readByte(); 424 | tempObj.movingData.angle = packet.readWord(); 425 | } 426 | 427 | tempObj.alive = packet.readByte(); 428 | tempObj.unknown1 = packet.readByte(); 429 | tempObj.unknown2 = packet.readByte(); 430 | //tempObj.unknown3 = packet.readByte(); //Deprecated by vsro client. No idea about isro. 431 | tempObj.berserkerActive = packet.readByte(); 432 | tempObj.walkingSpeed = packet.readFloat(); 433 | tempObj.runningSpeed = packet.readFloat(); 434 | tempObj.berserkerSpeed = packet.readFloat(); 435 | 436 | tempObj.activeSkillsCount = packet.readByte(); 437 | tempObj.activeSkills = new Object(); 438 | for (var i = 0; i < tempObj.activeSkillsCount; i++) { 439 | var skillId; 440 | skillId = packet.readDWord(); 441 | tempObj.activeSkills[skillId] = new Object(); 442 | tempObj.activeSkills[skillId].id = skillId; 443 | tempObj.activeSkills[skillId].unknown4 = packet.readDWord(); 444 | }; 445 | 446 | tempObj.unknown5 = packet.readByte(); 447 | tempObj.unknown6 = packet.readByte(); 448 | tempObj.unknown7 = packet.readByte(); 449 | tempObj.type = packet.readByte(); 450 | 451 | this._bot.spawnManager.monsters[tempObj.uniqueId] = tempObj; 452 | console.log('================================='); 453 | console.log('Spawn monster: ' + monster.type); 454 | console.log('Unique ID: ' + tempObj.uniqueId + ' Model: ' + tempObj.model); 455 | console.log('================================='); 456 | } 457 | 458 | function SpawnParser$parseOther(packet, model) { 459 | var tempObj, other; 460 | tempObj = new Object(); 461 | 462 | tempObj.model = model; 463 | other = this._bot.gameData.chars[model]; 464 | tempObj.uniqueId = packet.readDWord(); 465 | if(other.type == 'INS_QUEST_TELEPORT') { 466 | tempObj.xSector = packet.readByte(); 467 | tempObj.ySector = packet.readByte(); 468 | tempObj.xOffset = packet.readFloat(); 469 | tempObj.zOffset = packet.readFloat(); 470 | tempObj.yOffset = packet.readFloat(); 471 | tempObj.position = packet.readWord(); 472 | tempObj.moving = packet.readByte(); 473 | tempObj.running = packet.readByte(); 474 | tempObj.unknown1 = packet.readWord(); 475 | tempObj.unknown2 = packet.readString(true); 476 | tempObj.unknown3 = packet.readDWord(); 477 | } 478 | this._bot.spawnManager.others[tempObj.uniqueId] = tempObj; 479 | console.log('================================='); 480 | console.log('Spawn other: ' + other.type); 481 | console.log('Unique ID: ' + tempObj.uniqueId + ' Model: ' + tempObj.model); 482 | console.log('================================='); 483 | } 484 | 485 | function SpawnParser$parseItem(packet, model) { 486 | var tempObj, item; 487 | tempObj = new Object(); 488 | 489 | tempObj.model = model; 490 | item = this._bot.gameData.items[model]; 491 | if(item.type.startsWith('ITEM_ETC_GOLD')) { 492 | tempObj.amount = packet.readDWord(); 493 | } 494 | 495 | if(item.type.startsWith('ITEM_QSP') || item.type.startsWith('ITEM_ETC_E090825') || item.type.startsWith('ITEM_QNO') || item.type.startsWith('ITEM_TRADE_SPECIAL_BOX')) { 496 | tempObj.name = packet.readString(true); 497 | } 498 | 499 | if(item.type.startsWith('ITEM_CH') || item.type.startsWith('ITEM_EU')) { 500 | tempObj.plus = packet.readByte(); 501 | } 502 | 503 | tempObj.uniqueId = packet.readDWord(); 504 | tempObj.xSector = packet.readByte(); 505 | tempObj.ySector = packet.readByte(); 506 | tempObj.xOffset = packet.readFloat(); 507 | tempObj.zOffset = packet.readFloat(); 508 | tempObj.yOffset = packet.readFloat(); 509 | tempObj.position = packet.readWord(); 510 | tempObj.owned = packet.readByte(); 511 | if(tempObj.owned == 1) { 512 | tempObj.ownerId = packet.readDWord(); 513 | } 514 | tempObj.itemBlued = packet.readByte(); 515 | 516 | this._bot.spawnManager.items[tempObj.uniqueId] = tempObj; 517 | console.log('================================='); 518 | console.log('Spawn item: ' + item.type); 519 | console.log('Unique ID: ' + tempObj.uniqueId + ' Model: ' + tempObj.model); 520 | console.log('================================='); 521 | 522 | } -------------------------------------------------------------------------------- /logic/server/ServerSpawns.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | var PacketWriter = require('../../packet/PacketWriter'); 3 | var functions = require('../../functions'); 4 | 5 | module.exports = { 6 | ServerSpawns: ServerSpawns 7 | }; 8 | 9 | var $ServerSpawns = ServerSpawns.prototype; 10 | $ServerSpawns.sendSpawns = ServerSpawns$sendSpawns; 11 | $ServerSpawns._sendChars = ServerSpawns$_sendChars; 12 | $ServerSpawns._sendGates = ServerSpawns$_sendGates; 13 | $ServerSpawns._sendPets = ServerSpawns$_sendPets; 14 | $ServerSpawns._sendNPCs = ServerSpawns$_sendNPCs; 15 | $ServerSpawns._sendMonsters = ServerSpawns$_sendMonsters; 16 | $ServerSpawns._sendOthers = ServerSpawns$_sendOthers; 17 | $ServerSpawns._sendItems = ServerSpawns$_sendItems; 18 | 19 | 20 | function ServerSpawns(bot) { 21 | this._bot = bot; 22 | this._maxSpawnsInPacket = 5; 23 | } 24 | 25 | function ServerSpawns$sendSpawns(client) { 26 | this._sendChars(client); 27 | this._sendGates(client); 28 | this._sendPets(client); 29 | this._sendNPCs(client); 30 | this._sendMonsters(client); 31 | this._sendOthers(client); 32 | this._sendItems(client); 33 | } 34 | 35 | function ServerSpawns$_sendChars(client) { 36 | var spawns, spawnCount, currentPacketCount, sentPacketCount, pBegin, pData, Pend; 37 | 38 | spawns = this._bot.spawnManager.characters; 39 | spawnCount = Object.keys(spawns).length; 40 | 41 | // Stop this function if there's no spawned objects 42 | if(!spawnCount) { 43 | return; 44 | } 45 | 46 | currentPacketCount = 0; 47 | sentPacketCount = 0; 48 | 49 | pData = new PacketWriter(); 50 | pEnd = new PacketWriter(); 51 | 52 | for (var uniqueId in spawns) { 53 | var spawn; 54 | 55 | spawn = spawns[uniqueId]; 56 | 57 | pData.writeDWord(spawn.model); 58 | pData.writeByte(spawn.volume); 59 | pData.writeByte(spawn.rank); 60 | pData.writeByte(spawn.icons); 61 | pData.writeByte(spawn.unknown1); 62 | pData.writeByte(spawn.maxSlots); 63 | pData.writeByte(spawn.itemCount); 64 | 65 | for (var itemId in spawn.items) { 66 | var item, itemData; 67 | item = spawn.items[itemId]; 68 | pData.writeDWord(itemId); 69 | itemData = this._bot.gameData.items[itemId]; 70 | if(itemData.type.startsWith('ITEM_CH') || itemData.type.startsWith('ITEM_EU') || itemData.type.startsWith('ITEM_FORT') || itemData.type.startsWith('ITEM_ROC_CH') || itemData.type.startsWith('ITEM_ROC_EU')) { 71 | pData.writeByte(item.plus); 72 | } 73 | 74 | }; 75 | 76 | pData.writeByte(spawn.maxAvatarSlots); 77 | pData.writeByte(spawn.avatarCount); 78 | 79 | for (var avatarId in spawn.avatars) { 80 | var avatar; 81 | avatar = spawn.avatars[avatarId]; 82 | pData.writeDWord(avatarId); 83 | pData.writeByte(avatar.plus); 84 | }; 85 | 86 | pData.writeByte(spawn.mask); 87 | if(spawn.mask == 1) { 88 | var mask; 89 | pData.writeDWord(spawn.maskData.id); 90 | mask = this._bot.gameData.chars[spawn.maskData.id]; 91 | if(mask.type.startsWith('CHAR')) { 92 | pData.writeByte(spawn.maskData.unknown1); 93 | pData.writeByte(spawn.maskData.count); 94 | for (var i = 0; i < spawn.maskData.count; i++) { 95 | pData.writeDWord(spawn.maskData.unknownData[i]); 96 | }; 97 | } 98 | } 99 | 100 | pData.writeDWord(spawn.uniqueId); 101 | pData.writeByte(spawn.xSector); 102 | pData.writeByte(spawn.ySector); 103 | pData.writeFloat(spawn.xOffset); 104 | pData.writeFloat(spawn.zOffset); 105 | pData.writeFloat(spawn.yOffset); 106 | pData.writeWord(spawn.position); 107 | pData.writeByte(spawn.moving); 108 | pData.writeByte(spawn.running); 109 | if(spawn.moving == 1) { 110 | pData.writeByte(spawn.movingData.xSector); 111 | pData.writeByte(spawn.movingData.ySector); 112 | 113 | if(spawn.movingData.ySector == 0x80) { 114 | pData.writeWord(spawn.movingData.xOffset); 115 | pData.writeWord(spawn.movingData.xOffset2); 116 | 117 | pData.writeWord(spawn.movingData.zOffset); 118 | pData.writeWord(spawn.movingData.zOffset2); 119 | 120 | pData.writeWord(spawn.movingData.yOffset); 121 | pData.writeWord(spawn.movingData.yOffset2); 122 | } else { 123 | pData.writeWord(spawn.movingData.xOffset); 124 | pData.writeWord(spawn.movingData.zOffset); 125 | pData.writeWord(spawn.movingData.yOffset); 126 | } 127 | } else { 128 | pData.writeByte(spawn.movingData.noDestination); 129 | pData.writeWord(spawn.movingData.angle); 130 | } 131 | 132 | pData.writeByte(spawn.unknown2); 133 | pData.writeByte(spawn.alive); 134 | pData.writeByte(spawn.unknown3); 135 | pData.writeByte(spawn.unknown4); 136 | pData.writeDWord(spawn.walkingSpeed); 137 | pData.writeDWord(spawn.runningSpeed); 138 | pData.writeDWord(spawn.berserkerSpeed); 139 | 140 | pData.writeByte(spawn.activeSkillsCount); 141 | 142 | for (var skillId in spawn.activeSkills) { 143 | var skill, skillData; 144 | skill = spawn.activeSkills[skillId]; 145 | skillData = this._bot.gameData.skills[skillId]; 146 | pData.writeDWord(skillId); 147 | pData.writeDWord(skill.tempId); 148 | if(skillData.type.startsWith('SKILL_EU_CLERIC_RECOVERYA_GROUP') || skillData.type.startsWith('SKILL_EU_BARD_BATTLAA_GUARD') || skillData.type.startsWith('SKILL_EU_BARD_DANCEA') || skillData.type.startsWith('SKILL_EU_BARD_SPEEDUPA_HITRATE')) { 149 | pData.writeByte(skill.unknown1); 150 | } 151 | 152 | }; 153 | 154 | pData.writeString(spawn.name); 155 | if(spawn.trade == 1) { 156 | pData.writeQWord(spawn.unknown6); 157 | pData.writeString(spawn.guildName); 158 | } else { 159 | pData.writeByte(spawn.jobType); 160 | pData.writeByte(spawn.jobLevel); 161 | pData.writeByte(spawn.pvpState); 162 | pData.writeByte(spawn.transport); 163 | pData.writeByte(spawn.unknown7); 164 | if(spawn.transport == 1){ 165 | pData.writeDWord(spawn.transportId); 166 | } 167 | pData.writeByte(spawn.unknown8); 168 | pData.writeByte(spawn.stallFlag); 169 | 170 | pData.writeByte(spawn.unknown9); 171 | pData.writeString(spawn.guildName); 172 | pData.writeDWord(spawn.guildId); 173 | pData.writeString(spawn.grantName); 174 | pData.writeDWord(spawn.unknown10); 175 | pData.writeDWord(spawn.unknown11); 176 | pData.writeDWord(spawn.unknown12); 177 | pData.writeWord(spawn.unknown13); 178 | if(spawn.stallFlag == 4) { 179 | pData.writeString(spawn.stallName); 180 | pData.writeDWord(spawn.unknown14); 181 | } 182 | /* 183 | pData.writeByte(spawn.unknown8); 184 | pData.writeByte(spawn.unknown9); 185 | if(spawn.unknown9 == 1) { 186 | pData.writeDWord(spawn.unknown10); 187 | } 188 | pData.writeByte(spawn.jobType); 189 | pData.writeByte(spawn.stallFlag); 190 | pData.writeString(spawn.guildName); 191 | pData.writeDWord(spawn.guildId); 192 | pData.writeString(spawn.grantName); 193 | pData.writeDWord(spawn.unknown11); 194 | pData.writeDWord(spawn.unknown12); 195 | pData.writeDWord(spawn.unknown13); 196 | pData.writeWord(spawn.unknown14); 197 | if(spawn.stallFlag == 4) { 198 | pData.writeString(spawn.stallName); 199 | pData.writeDWord(spawn.unknown15); 200 | } 201 | */ 202 | } 203 | 204 | pData.writeWord(spawn.PKFlag); 205 | 206 | 207 | 208 | //================= SEND STACKED PACKET ===================== 209 | 210 | sentPacketCount += 1; 211 | currentPacketCount += 1; 212 | 213 | if(sentPacketCount % this._maxSpawnsInPacket == 0 || sentPacketCount >= spawnCount) { 214 | 215 | pBegin = new PacketWriter(); 216 | pBegin.writeByte(1); //Spawn action. 217 | pBegin.writeWord(currentPacketCount); 218 | 219 | this._bot.server.send(client, this._bot.opcodes.SERVER.GROUPSPAWN_BEGIN, pBegin, false); 220 | this._bot.server.send(client, this._bot.opcodes.SERVER.GROUPSPAWN_DATA, pData, false); 221 | this._bot.server.send(client, this._bot.opcodes.SERVER.GROUPSPAWN_END, pEnd, false); 222 | 223 | pData = new PacketWriter(); 224 | 225 | currentPacketCount = 0; 226 | } 227 | 228 | }; 229 | 230 | } 231 | 232 | function ServerSpawns$_sendGates(client) { 233 | var spawns, spawnCount, currentPacketCount, sentPacketCount, pBegin, pData, Pend; 234 | 235 | spawns = this._bot.spawnManager.gates; 236 | spawnCount = Object.keys(spawns).length; 237 | 238 | // Stop this function if there's no spawned objects 239 | if(!spawnCount) { 240 | return; 241 | } 242 | 243 | currentPacketCount = 0; 244 | sentPacketCount = 0; 245 | 246 | pData = new PacketWriter(); 247 | pEnd = new PacketWriter(); 248 | 249 | for (var uniqueId in spawns) { 250 | var spawn; 251 | 252 | spawn = spawns[uniqueId]; 253 | 254 | pData.writeDWord(spawn.model); 255 | pData.writeDWord(spawn.uniqueId); 256 | pData.writeByte(spawn.unknown1); 257 | pData.writeByte(spawn.unknown2); 258 | pData.writeFloat(spawn.unknown3); 259 | pData.writeFloat(spawn.unknown4); 260 | pData.writeFloat(spawn.unknown5); 261 | pData.writeWord(spawn.unknown6); 262 | pData.writeDWord(spawn.unknown7); 263 | pData.writeQWord(spawn.unknown8); 264 | 265 | //================= SEND STACKED PACKET ===================== 266 | 267 | sentPacketCount += 1; 268 | currentPacketCount += 1; 269 | 270 | if(sentPacketCount % this._maxSpawnsInPacket == 0 || sentPacketCount >= spawnCount) { 271 | 272 | pBegin = new PacketWriter(); 273 | pBegin.writeByte(1); //Spawn action. 274 | pBegin.writeWord(currentPacketCount); 275 | 276 | this._bot.server.send(client, this._bot.opcodes.SERVER.GROUPSPAWN_BEGIN, pBegin, false); 277 | this._bot.server.send(client, this._bot.opcodes.SERVER.GROUPSPAWN_DATA, pData, false); 278 | this._bot.server.send(client, this._bot.opcodes.SERVER.GROUPSPAWN_END, pEnd, false); 279 | 280 | pData = new PacketWriter(); 281 | 282 | currentPacketCount = 0; 283 | } 284 | 285 | }; 286 | 287 | } 288 | 289 | function ServerSpawns$_sendPets(client) { 290 | var spawns, spawnCount, currentPacketCount, sentPacketCount, pBegin, pData, Pend; 291 | 292 | spawns = this._bot.spawnManager.pets; 293 | spawnCount = Object.keys(spawns).length; 294 | 295 | // Stop this function if there's no spawned objects 296 | if(!spawnCount) { 297 | return; 298 | } 299 | 300 | currentPacketCount = 0; 301 | sentPacketCount = 0; 302 | 303 | pData = new PacketWriter(); 304 | pEnd = new PacketWriter(); 305 | 306 | for (var uniqueId in spawns) { 307 | var spawn, petData, tempType; 308 | 309 | spawn = spawns[uniqueId]; 310 | 311 | petData = this._bot.gameData.chars[spawn.model]; 312 | 313 | pData.writeDWord(spawn.model); 314 | pData.writeDWord(spawn.uniqueId); 315 | pData.writeByte(spawn.xSector); 316 | pData.writeByte(spawn.ySector); 317 | pData.writeFloat(spawn.xOffset); 318 | pData.writeFloat(spawn.zOffset); 319 | pData.writeFloat(spawn.yOffset); 320 | pData.writeWord(spawn.position); 321 | pData.writeByte(spawn.moving); 322 | 323 | if(spawn.moving == 1) { 324 | pData.writeByte(spawn.movingData.xSector); 325 | pData.writeByte(spawn.movingData.ySector); 326 | 327 | if(spawn.movingData.ySector == 0x80) { 328 | pData.writeWord(spawn.movingData.xOffset); 329 | pData.writeWord(spawn.movingData.xOffset2); 330 | 331 | pData.writeWord(spawn.movingData.zOffset); 332 | pData.writeWord(spawn.movingData.zOffset2); 333 | 334 | pData.writeWord(spawn.movingData.yOffset); 335 | pData.writeWord(spawn.movingData.yOffset2); 336 | } else { 337 | pData.writeWord(spawn.movingData.xOffset); 338 | pData.writeWord(spawn.movingData.zOffset); 339 | pData.writeWord(spawn.movingData.yOffset); 340 | } 341 | } else { 342 | pData.writeByte(spawn.movingData.noDestination); 343 | pData.writeWord(spawn.movingData.angle); 344 | } 345 | 346 | pData.writeByte(spawn.unknown1); 347 | pData.writeByte(spawn.unknown2); 348 | pData.writeByte(spawn.unknown3); 349 | pData.writeByte(spawn.unknown4); 350 | pData.writeByte(spawn.unknown5); 351 | pData.writeFloat(spawn.unknown6); 352 | pData.writeFloat(spawn.speed); 353 | pData.writeFloat(spawn.unknown7); 354 | pData.writeWord(spawn.unknown8); 355 | 356 | tempType = petData.type; 357 | if(petData.type.startsWith('COS_P_BEAR') || petData.type.startsWith('COS_P_FOX') || petData.type.startsWith('COS_P_KANGAROO') || petData.type.startsWith('COS_P_PENGUIN') || petData.type.startsWith('COS_P_RAVEN') || petData.type.startsWith('COS_P_JINN') || petData.type.startsWith('COS_P_WOLF') || petData.type.startsWith('COS_P_WOLF_WHITE') || petData.type.startsWith('COS_P_WOLF_WHITE_SMALL')) { 358 | tempType = tempType.substring(0, tempType.length - 4) 359 | } 360 | if(tempType.startsWith('COS_C') || tempType.startsWith('COS_T_DHORSE')) { 361 | //Do nothing 362 | } else if(this._bot.gameData.petTypes.grabPets.indexOf(tempType) != -1) { 363 | pData.writeString(spawn.petName); 364 | pData.writeString(spawn.ownerName); 365 | pData.writeByte(spawn.unknown9); 366 | pData.writeDWord(spawn.ownerId); 367 | } else if(this._bot.gameData.petTypes.attackPets.indexOf(tempType) != -1) { 368 | pData.writeString(spawn.petName); 369 | pData.writeString(spawn.ownerName); 370 | pData.writeByte(spawn.unknown10); 371 | pData.writeByte(spawn.unknown11); 372 | pData.writeDWord(spawn.ownerId); 373 | 374 | if(spawn.b1 == 255 && spawn.b2 == 255 && spawn.b3 == 255 && spawn.b4 == 255) { 375 | pData.writeByte(spawn.b1); 376 | pData.writeByte(spawn.b2); 377 | pData.writeByte(spawn.b3); 378 | pData.writeByte(spawn.b4); 379 | pData.writeWord(spawn.unknown12); 380 | } 381 | } else if(tempType.contains('COS_T')) { 382 | pData.writeString(spawn.ownerName); 383 | pData.writeByte(spawn.unknown13); 384 | pData.writeByte(spawn.unknown14); 385 | pData.writeDWord(spawn.unknown15); 386 | pData.writeByte(spawn.unknown16); 387 | } else if (tempType.startsWith('TRADE_COS_QUEST_TRADE')) { 388 | pData.writeString(spawn.ownerName); 389 | pData.writeWord(spawn.unknown17); 390 | pData.writeDWord(spawn.unknown18); 391 | } else { 392 | pData.writeString(spawn.ownerName); 393 | pData.writeByte(spawn.unknown19); 394 | pData.writeByte(spawn.unknown20); 395 | pData.writeDWord(spawn.unknown21); 396 | } 397 | 398 | 399 | //================= SEND STACKED PACKET ===================== 400 | 401 | sentPacketCount += 1; 402 | currentPacketCount += 1; 403 | 404 | if(sentPacketCount % this._maxSpawnsInPacket == 0 || sentPacketCount >= spawnCount) { 405 | 406 | pBegin = new PacketWriter(); 407 | pBegin.writeByte(1); //Spawn action. 408 | pBegin.writeWord(currentPacketCount); 409 | 410 | this._bot.server.send(client, this._bot.opcodes.SERVER.GROUPSPAWN_BEGIN, pBegin, false); 411 | this._bot.server.send(client, this._bot.opcodes.SERVER.GROUPSPAWN_DATA, pData, false); 412 | this._bot.server.send(client, this._bot.opcodes.SERVER.GROUPSPAWN_END, pEnd, false); 413 | 414 | pData = new PacketWriter(); 415 | 416 | currentPacketCount = 0; 417 | } 418 | 419 | }; 420 | 421 | } 422 | 423 | function ServerSpawns$_sendNPCs(client) { 424 | var spawns, spawnCount, currentPacketCount, sentPacketCount, pBegin, pData, Pend; 425 | 426 | spawns = this._bot.spawnManager.NPCs; 427 | spawnCount = Object.keys(spawns).length; 428 | 429 | // Stop this function if there's no spawned objects 430 | if(!spawnCount) { 431 | return; 432 | } 433 | 434 | currentPacketCount = 0; 435 | sentPacketCount = 0; 436 | 437 | pData = new PacketWriter(); 438 | pEnd = new PacketWriter(); 439 | 440 | for (var uniqueId in spawns) { 441 | var spawn; 442 | 443 | spawn = spawns[uniqueId]; 444 | 445 | pData.writeDWord(spawn.model); 446 | pData.writeDWord(spawn.uniqueId); 447 | pData.writeByte(spawn.xSector); 448 | pData.writeByte(spawn.ySector); 449 | pData.writeFloat(spawn.xOffset); 450 | pData.writeFloat(spawn.zOffset); 451 | pData.writeFloat(spawn.yOffset); 452 | pData.writeWord(spawn.position); 453 | pData.writeByte(spawn.moving); 454 | pData.writeByte(spawn.running); 455 | if(spawn.moving == 1) { 456 | pData.writeByte(spawn.movingData.xSector); 457 | pData.writeByte(spawn.movingData.ySector); 458 | 459 | if(spawn.movingData.ySector == 0x80) { 460 | pData.writeWord(spawn.movingData.xOffset); 461 | pData.writeWord(spawn.movingData.xOffset2); 462 | 463 | pData.writeWord(spawn.movingData.zOffset); 464 | pData.writeWord(spawn.movingData.zOffset2); 465 | 466 | pData.writeWord(spawn.movingData.yOffset); 467 | pData.writeWord(spawn.movingData.yOffset2); 468 | } else { 469 | pData.writeWord(spawn.movingData.xOffset); 470 | pData.writeWord(spawn.movingData.zOffset); 471 | pData.writeWord(spawn.movingData.yOffset); 472 | } 473 | } else { 474 | pData.writeByte(spawn.movingData.noDestination); 475 | pData.writeWord(spawn.movingData.angle); 476 | } 477 | 478 | pData.writeByte(spawn.alive); 479 | pData.writeByte(spawn.unknown1); 480 | pData.writeByte(spawn.unknown2); 481 | pData.writeByte(spawn.unknown3); 482 | pData.writeDWord(spawn.walkingSpeed); 483 | pData.writeDWord(spawn.runningSpeed); 484 | pData.writeDWord(spawn.berserkerSpeed); 485 | pData.writeByte(spawn.unknown4); 486 | pData.writeByte(spawn.check); 487 | 488 | if(spawn.check != 0) { 489 | pData.writeByte(spawn.count); 490 | for (var i = 0; i < spawn.count; i++) { 491 | pData.writeByte(spawn.unknown5[i]); 492 | }; 493 | } 494 | 495 | //================= SEND STACKED PACKET ===================== 496 | 497 | sentPacketCount += 1; 498 | currentPacketCount += 1; 499 | 500 | if(sentPacketCount % this._maxSpawnsInPacket == 0 || sentPacketCount >= spawnCount) { 501 | 502 | pBegin = new PacketWriter(); 503 | pBegin.writeByte(1); //Spawn action. 504 | pBegin.writeWord(currentPacketCount); 505 | 506 | this._bot.server.send(client, this._bot.opcodes.SERVER.GROUPSPAWN_BEGIN, pBegin, false); 507 | this._bot.server.send(client, this._bot.opcodes.SERVER.GROUPSPAWN_DATA, pData, false); 508 | this._bot.server.send(client, this._bot.opcodes.SERVER.GROUPSPAWN_END, pEnd, false); 509 | 510 | pData = new PacketWriter(); 511 | 512 | currentPacketCount = 0; 513 | } 514 | 515 | }; 516 | 517 | } 518 | 519 | function ServerSpawns$_sendMonsters(client) { 520 | var spawns, spawnCount, currentPacketCount, sentPacketCount, pBegin, pData, Pend; 521 | 522 | spawns = this._bot.spawnManager.monsters; 523 | spawnCount = Object.keys(spawns).length; 524 | 525 | // Stop this function if there's no spawned objects 526 | if(!spawnCount) { 527 | return; 528 | } 529 | 530 | currentPacketCount = 0; 531 | sentPacketCount = 0; 532 | 533 | pData = new PacketWriter(); 534 | pEnd = new PacketWriter(); 535 | 536 | for (var uniqueId in spawns) { 537 | var spawn; 538 | 539 | spawn = spawns[uniqueId]; 540 | 541 | pData.writeDWord(spawn.model); 542 | pData.writeDWord(spawn.uniqueId); 543 | 544 | 545 | pData.writeByte(spawn.xSector); 546 | pData.writeByte(spawn.ySector); 547 | pData.writeFloat(spawn.xOffset); 548 | pData.writeFloat(spawn.zOffset); 549 | pData.writeFloat(spawn.yOffset); 550 | pData.writeWord(spawn.position); 551 | pData.writeByte(spawn.moving); 552 | pData.writeByte(spawn.running); 553 | if(spawn.moving == 1) { 554 | pData.writeByte(spawn.movingData.xSector); 555 | pData.writeByte(spawn.movingData.ySector); 556 | 557 | if(spawn.movingData.ySector == 0x80) { 558 | pData.writeWord(spawn.movingData.xOffset); 559 | pData.writeWord(spawn.movingData.xOffset2); 560 | 561 | pData.writeWord(spawn.movingData.zOffset); 562 | pData.writeWord(spawn.movingData.zOffset2); 563 | 564 | pData.writeWord(spawn.movingData.yOffset); 565 | pData.writeWord(spawn.movingData.yOffset2); 566 | } else { 567 | pData.writeWord(spawn.movingData.xOffset); 568 | pData.writeWord(spawn.movingData.zOffset); 569 | pData.writeWord(spawn.movingData.yOffset); 570 | } 571 | } else { 572 | pData.writeByte(spawn.movingData.noDestination); 573 | pData.writeWord(spawn.movingData.angle); 574 | } 575 | 576 | pData.writeByte(spawn.alive); 577 | pData.writeByte(spawn.unknown1); 578 | pData.writeByte(spawn.unknown2); 579 | pData.writeByte(spawn.berserkerActive); 580 | pData.writeFloat(spawn.walkingSpeed); 581 | pData.writeFloat(spawn.runningSpeed); 582 | pData.writeFloat(spawn.berserkerSpeed); 583 | 584 | pData.writeByte(spawn.activeSkillsCount); 585 | 586 | for (var skillId in spawn.activeSkills) { 587 | var skill; 588 | skill = spawn.activeSkills[skillId]; 589 | pData.writeDWord(skillId); 590 | pData.writeDWord(skill.unknown4); 591 | }; 592 | 593 | pData.writeByte(spawn.unknown5); 594 | pData.writeByte(spawn.unknown6); 595 | pData.writeByte(spawn.unknown7); 596 | pData.writeByte(spawn.type); 597 | 598 | //================= SEND STACKED PACKET ===================== 599 | 600 | sentPacketCount += 1; 601 | currentPacketCount += 1; 602 | 603 | if(sentPacketCount % this._maxSpawnsInPacket == 0 || sentPacketCount >= spawnCount) { 604 | 605 | pBegin = new PacketWriter(); 606 | pBegin.writeByte(1); //Spawn action. 607 | pBegin.writeWord(currentPacketCount); 608 | 609 | this._bot.server.send(client, this._bot.opcodes.SERVER.GROUPSPAWN_BEGIN, pBegin, false); 610 | this._bot.server.send(client, this._bot.opcodes.SERVER.GROUPSPAWN_DATA, pData, false); 611 | this._bot.server.send(client, this._bot.opcodes.SERVER.GROUPSPAWN_END, pEnd, false); 612 | 613 | pData = new PacketWriter(); 614 | 615 | currentPacketCount = 0; 616 | } 617 | 618 | }; 619 | 620 | } 621 | 622 | function ServerSpawns$_sendOthers(client) { 623 | var spawns, spawnCount, currentPacketCount, sentPacketCount, pBegin, pData, Pend; 624 | 625 | spawns = this._bot.spawnManager.others; 626 | spawnCount = Object.keys(spawns).length; 627 | 628 | // Stop this function if there's no spawned objects 629 | if(!spawnCount) { 630 | return; 631 | } 632 | 633 | currentPacketCount = 0; 634 | sentPacketCount = 0; 635 | 636 | pData = new PacketWriter(); 637 | pEnd = new PacketWriter(); 638 | 639 | for (var uniqueId in spawns) { 640 | var spawn, otherData; 641 | 642 | spawn = spawns[uniqueId]; 643 | 644 | otherData = this._bot.gameData.chars[spawn.model]; 645 | 646 | pData.writeDWord(spawn.model); 647 | pData.writeDWord(spawn.uniqueId); 648 | 649 | if(otherData.type == 'INS_QUEST_TELEPORT') { 650 | pData.writeByte(spawn.xSector); 651 | pData.writeByte(spawn.ySector); 652 | pData.writeFloat(spawn.xOffset); 653 | pData.writeFloat(spawn.zOffset); 654 | pData.writeFloat(spawn.yOffset); 655 | pData.writeWord(spawn.position); 656 | pData.writeByte(spawn.moving); 657 | pData.writeByte(spawn.running); 658 | pData.writeWord(spawn.unknown1); 659 | pData.writeString(spawn.unknown2); 660 | pData.writeDWord(spawn.unknown3); 661 | } 662 | 663 | 664 | //================= SEND STACKED PACKET ===================== 665 | 666 | sentPacketCount += 1; 667 | currentPacketCount += 1; 668 | 669 | if(sentPacketCount % this._maxSpawnsInPacket == 0 || sentPacketCount >= spawnCount) { 670 | 671 | pBegin = new PacketWriter(); 672 | pBegin.writeByte(1); //Spawn action. 673 | pBegin.writeWord(currentPacketCount); 674 | 675 | this._bot.server.send(client, this._bot.opcodes.SERVER.GROUPSPAWN_BEGIN, pBegin, false); 676 | this._bot.server.send(client, this._bot.opcodes.SERVER.GROUPSPAWN_DATA, pData, false); 677 | this._bot.server.send(client, this._bot.opcodes.SERVER.GROUPSPAWN_END, pEnd, false); 678 | 679 | pData = new PacketWriter(); 680 | 681 | currentPacketCount = 0; 682 | } 683 | 684 | }; 685 | 686 | } 687 | 688 | function ServerSpawns$_sendItems(client) { 689 | var spawns, spawnCount, currentPacketCount, sentPacketCount, pBegin, pData, Pend; 690 | 691 | spawns = this._bot.spawnManager.items; 692 | spawnCount = Object.keys(spawns).length; 693 | 694 | // Stop this function if there's no spawned objects 695 | if(!spawnCount) { 696 | return; 697 | } 698 | 699 | currentPacketCount = 0; 700 | sentPacketCount = 0; 701 | 702 | pData = new PacketWriter(); 703 | pEnd = new PacketWriter(); 704 | 705 | for (var uniqueId in spawns) { 706 | var spawn, itemData; 707 | 708 | spawn = spawns[uniqueId]; 709 | 710 | itemData = this._bot.gameData.items[spawn.model]; 711 | 712 | pData.writeDWord(spawn.model); 713 | 714 | if(itemData.type.startsWith('ITEM_ETC_GOLD')) { 715 | pData.writeDWord(spawn.amount); 716 | } 717 | 718 | if(itemData.type.startsWith('ITEM_QSP') || itemData.type.startsWith('ITEM_ETC_E090825') || itemData.type.startsWith('ITEM_QNO') || itemData.type.startsWith('ITEM_TRADE_SPECIAL_BOX')) { 719 | pData.writeString(spawn.name); 720 | } 721 | 722 | if(itemData.type.startsWith('ITEM_CH') || itemData.type.startsWith('ITEM_EU')) { 723 | pData.writeByte(spawn.plus); 724 | } 725 | 726 | pData.writeDWord(spawn.uniqueId); 727 | pData.writeByte(spawn.xSector); 728 | pData.writeByte(spawn.ySector); 729 | pData.writeFloat(spawn.xOffset); 730 | pData.writeFloat(spawn.zOffset); 731 | pData.writeFloat(spawn.yOffset); 732 | pData.writeWord(spawn.position); 733 | pData.writeByte(spawn.owned); 734 | if(spawn.owned == 1) { 735 | pData.writeDWord(spawn.ownerId); 736 | } 737 | pData.writeByte(spawn.itemBlued); 738 | 739 | //================= SEND STACKED PACKET ===================== 740 | 741 | sentPacketCount += 1; 742 | currentPacketCount += 1; 743 | 744 | if(sentPacketCount % this._maxSpawnsInPacket == 0 || sentPacketCount >= spawnCount) { 745 | 746 | pBegin = new PacketWriter(); 747 | pBegin.writeByte(1); //Spawn action. 748 | pBegin.writeWord(currentPacketCount); 749 | 750 | this._bot.server.send(client, this._bot.opcodes.SERVER.GROUPSPAWN_BEGIN, pBegin, false); 751 | this._bot.server.send(client, this._bot.opcodes.SERVER.GROUPSPAWN_DATA, pData, false); 752 | this._bot.server.send(client, this._bot.opcodes.SERVER.GROUPSPAWN_END, pEnd, false); 753 | 754 | pData = new PacketWriter(); 755 | 756 | currentPacketCount = 0; 757 | } 758 | 759 | }; 760 | 761 | } -------------------------------------------------------------------------------- /security/Security.js: -------------------------------------------------------------------------------- 1 | var crypto = require('crypto'); 2 | var Long = require('long'); 3 | var securitytable = require('./securitytable'); 4 | var helper = require('../helper'); 5 | var Blowfish = require('../blowfish/Blowfish'); 6 | var PacketReader = require('../packet/PacketReader'); 7 | var PacketWriter = require('../packet/PacketWriter'); 8 | 9 | var $Security = Security.prototype; 10 | $Security.generateValue = Security$generateValue; 11 | $Security.setupCountByte = Security$setupCountByte; 12 | $Security.gPowXmodP = Security$gPowXmodP; 13 | $Security.keyTransformValue = Security$keyTransformValue; 14 | $Security.generateCountByte = Security$generateCountByte; 15 | $Security.generateCheckByte = Security$generateCheckByte; 16 | $Security.decode = Security$decode; 17 | $Security.getOutputLength = Security$getOutputLength; 18 | $Security.handshake10 = Security$handshake10; 19 | $Security.handshakeE = Security$handshakeE; 20 | $Security.formatPacket = Security$formatPacket; 21 | $Security.handshake = Security$handshake; 22 | $Security._fromSecurityFlags = Security$_fromSecurityFlags; 23 | $Security._toSecurityFlags = Security$_toSecurityFlags; 24 | $Security.generateSecurity = Security$generateSecurity; 25 | 26 | module.exports = Security; 27 | 28 | function Security() { 29 | this.m_initial_blowfish_key = new Buffer([0, 0, 0, 0, 0, 0, 0, 0]); 30 | this.m_seed_count = 0; 31 | this.m_crc_seed = 0; 32 | this.m_handshake_blowfish_key = new Buffer([0, 0 ,0 ,0 ,0 ,0 ,0 ,0]); 33 | this.m_value_g = 0; 34 | this.m_value_p = 0; 35 | this.m_value_A = 0; 36 | this.m_value_x = 0; 37 | this.m_value_B = 0; 38 | this.m_value_K = 0; 39 | this.m_count_byte_seeds = new Buffer([0,0,0]); 40 | this.m_client_key = new Buffer([0, 0, 0, 0, 0, 0, 0, 0]); 41 | this.m_challenge_key = 0; 42 | this.key_array = new Buffer([0, 0, 0, 0, 0, 0, 0, 0]); 43 | 44 | this.m_client_security = false; 45 | this.m_security_flag = 0; 46 | this.m_security_flags = { 47 | none: 0, 48 | blowfish: 0, 49 | security_bytes: 0, 50 | handshake: 0, 51 | handshake_response: 0, 52 | _6: 0, 53 | _7: 0, 54 | _8: 0, 55 | }; 56 | this.m_accepted_handshake = false; 57 | this.m_started_handshake = false; 58 | 59 | this.m_blowfish = new Blowfish(); 60 | 61 | this.m_identity_flag = 0; 62 | this.m_identity_name = "SR_Client"; 63 | }; 64 | 65 | function Security$generateValue(val) { 66 | for (var i = 0; i < 32; ++i) { 67 | val = ( 68 | ( 69 | ( 70 | ( 71 | ( 72 | ( 73 | ( 74 | ( 75 | ( 76 | ( 77 | (val >>> 2) ^ val 78 | ) >>> 2 79 | ) ^ val 80 | ) >>> 1 81 | ) ^ val 82 | ) >>> 1 83 | ) ^ val 84 | ) >>> 1 85 | ) ^ val 86 | ) & 1 87 | ) | ( 88 | ( 89 | ( 90 | (val & 1) << 31 91 | ) | ( 92 | val >>> 1 93 | ) 94 | ) & 0xFFFFFFFE 95 | ); 96 | } 97 | val = helper.toUInt32(val); 98 | return val; 99 | } 100 | 101 | function Security$setupCountByte(seed) { 102 | if (seed == 0) seed = 0x9ABFB3B6; 103 | var mut = seed; 104 | var mut1 = this.generateValue(mut); 105 | mut = mut1; 106 | var mut2 = this.generateValue(mut); 107 | mut = mut2; 108 | var mut3 = this.generateValue(mut); 109 | mut = mut3; 110 | mut = this.generateValue(mut); 111 | 112 | var byte1 = ((mut & 0xff) ^ (mut3 & 0xff)); 113 | var byte2 = ((mut1 & 0xff) ^ (mut2 & 0xff)); 114 | if (byte1 == 0) byte1== 1; 115 | if (byte2 == 0) byte2 == 1; 116 | 117 | this.m_count_byte_seeds[0] = (byte1 ^ byte2); 118 | this.m_count_byte_seeds[1] = byte2; 119 | this.m_count_byte_seeds[2] = byte1; 120 | //Should work, compared results with c# 121 | } 122 | 123 | function Security$gPowXmodP(P, X, G) { 124 | var result = Long.fromNumber(1); //Y U HAVE NO 64BIT INT?! 125 | var mult = Long.fromNumber(G); 126 | var modP = Long.fromNumber(P); 127 | if (X == 0) 128 | { 129 | return 1; 130 | } 131 | while (X != 0) 132 | { 133 | if ((X & 1) > 0) 134 | { 135 | 136 | result = result.multiply(mult); 137 | result = result.modulo(modP); 138 | } 139 | X = X >>> 1; 140 | mult = mult.multiply(mult); 141 | mult = mult.modulo(modP); 142 | } 143 | 144 | 145 | return result.toInt(); 146 | } 147 | 148 | function Security$keyTransformValue(val1, val2, key, key_byte) { 149 | var stream = new Buffer(8); 150 | stream.writeUInt32LE(val1, 0); 151 | stream.writeUInt32LE(val2, 4); 152 | 153 | stream[0] ^= (stream[0] + helper.LOBYTE_(helper.LOWORD_(key)) + key_byte); 154 | stream[1] ^= (stream[1] + helper.HIBYTE_(helper.LOWORD_(key)) + key_byte); 155 | stream[2] ^= (stream[2] + helper.LOBYTE_(helper.HIWORD_(key)) + key_byte); 156 | stream[3] ^= (stream[3] + helper.HIBYTE_(helper.HIWORD_(key)) + key_byte); 157 | stream[4] ^= (stream[4] + helper.LOBYTE_(helper.LOWORD_(key)) + key_byte); 158 | stream[5] ^= (stream[5] + helper.HIBYTE_(helper.LOWORD_(key)) + key_byte); 159 | stream[6] ^= (stream[6] + helper.LOBYTE_(helper.HIWORD_(key)) + key_byte); 160 | stream[7] ^= (stream[7] + helper.HIBYTE_(helper.HIWORD_(key)) + key_byte); 161 | return stream; //Should be correct 162 | } 163 | 164 | function Security$generateCountByte(update) { 165 | 166 | var result = helper.LOBYTE_(this.m_count_byte_seeds[2] * (~this.m_count_byte_seeds[0] + this.m_count_byte_seeds[1])); 167 | 168 | result = (result ^ (result >>> 4)); 169 | 170 | if (update) 171 | { 172 | this.m_count_byte_seeds[0] = result; 173 | } 174 | return result; 175 | } 176 | 177 | function Security$generateCheckByte(stream, offset, lenght) { 178 | var checksum = 0xFFFFFFFF; 179 | 180 | var lchecksum = Long.fromNumber(0xffffffff); 181 | var ff = Long.fromNumber(0xff); 182 | var moddedseed = this.m_crc_seed << 8; 183 | for (var x = offset; x < offset + lenght; ++x) 184 | { 185 | var tmp = Long.fromNumber(stream[x]); 186 | tmp = tmp.xor(lchecksum); 187 | tmp = tmp.and(ff); 188 | var index = moddedseed + tmp.toInt(); 189 | 190 | lchecksum = lchecksum.shiftRight(8); 191 | var tablevalue = Long.fromNumber(securitytable[index]); 192 | lchecksum = lchecksum.xor(tablevalue); 193 | 194 | } 195 | 196 | var tmp = lchecksum.shiftRightUnsigned(24); tmp = tmp.and(ff); 197 | var v1 = lchecksum.shiftRightUnsigned(8); v1 = v1.and(ff); 198 | var v2 = lchecksum.shiftRightUnsigned(16); v2 = v2.and(ff); 199 | var v3 = lchecksum.and(ff); 200 | 201 | tmp = tmp.add(v1); tmp = tmp.add(v2); tmp = tmp.add(v3); 202 | 203 | var test = tmp.toInt(); 204 | 205 | var bit = helper.LOBYTE_(test); 206 | return bit; 207 | } 208 | 209 | function Security$decode(data, offset, length) { 210 | return this.m_blowfish.Decode(data, offset, length); 211 | } 212 | 213 | function Security$getOutputLength(len) { 214 | return this.m_blowfish.GetOutputLength(len); 215 | } 216 | 217 | function Security$handshake10(packet) { 218 | var flag = packet.readByte(); 219 | var handshakelow = packet.readDWord(); 220 | var handshakehigh = packet.readDWord(); 221 | 222 | var handshakeKey = Long.fromBits(handshakelow, handshakehigh); 223 | var expectedKey = Long.fromBits(this.m_value_A, this.m_value_B); 224 | 225 | var challengekey = this.keyTransformValue(this.m_value_A, this.m_value_B, this.m_value_K, helper.LOBYTE_(helper.LOWORD_(this.m_value_A)) & 0x07); 226 | this.m_blowfish.Encode(challengekey, 0, 8); 227 | var key = Long.fromBits(challengekey.readUInt32LE(0), challengekey.readUInt32LE(4)); 228 | 229 | this.m_handshake_blowfish_key = this.keyTransformValue(this.m_handshake_blowfish_key.readUInt32LE(0), this.m_handshake_blowfish_key.readUInt32LE(4), this.m_value_K, 3); 230 | this.m_blowfish.Initialize(this.m_handshake_blowfish_key); 231 | // 232 | var response = new Buffer(6); 233 | response.writeUInt16LE(0, 0); 234 | response.writeUInt16LE(0x9000, 2); 235 | response.writeUInt16LE(0, 4); 236 | var countByte = this.generateCountByte(true); 237 | response.writeUInt8(countByte, 4); 238 | var checkByte = this.generateCheckByte(response, 0, 6); 239 | response.writeUInt8(checkByte, 5); 240 | 241 | return response; 242 | } 243 | 244 | function Security$handshakeE(packet){ 245 | var flag = packet.readByte(); 246 | 247 | var key1 = packet.readDWord(); 248 | var key2 = packet.readDWord(); 249 | 250 | this.m_initial_blowfish_key.writeUInt32LE(key1,0); 251 | this.m_initial_blowfish_key.writeUInt32LE(key2, 4); 252 | 253 | this.m_seed_count = packet.readDWord(); 254 | this.m_crc_seed = packet.readDWord(); 255 | this.setupCountByte(this.m_seed_count); 256 | 257 | var handshake1 = packet.readDWord(); 258 | var handshake2 = packet.readDWord(); 259 | 260 | this.m_handshake_blowfish_key.writeUInt32LE(handshake1,0); 261 | this.m_handshake_blowfish_key.writeUInt32LE(handshake2,4); 262 | 263 | this.m_value_g = packet.readDWord(); 264 | this.m_value_p = packet.readDWord(); 265 | this.m_value_A = packet.readDWord(); 266 | 267 | this.m_value_x = 0x33; //Soooo random ;) 268 | this.m_value_B = this.gPowXmodP(this.m_value_p, this.m_value_x, this.m_value_g); 269 | this.m_value_K = this.gPowXmodP(this.m_value_p, this.m_value_x, this.m_value_A); 270 | 271 | this.key_array = this.keyTransformValue(this.m_value_A, this.m_value_B, this.m_value_K, helper.LOBYTE_(helper.LOWORD_(this.m_value_K)) & 0x03); 272 | 273 | this.m_client_key = this.keyTransformValue(this.m_value_B, this.m_value_A, this.m_value_K, helper.LOBYTE_(helper.LOWORD_(this.m_value_B)) & 0x07); 274 | 275 | 276 | 277 | this.m_blowfish.Initialize(this.key_array); 278 | this.m_client_key = this.m_blowfish.Encode(this.m_client_key,0,8).buff; 279 | var response = new Buffer(18); 280 | var payload = new Buffer(12); 281 | 282 | payload.writeUInt32LE(this.m_value_B, 0); 283 | this.m_client_key.copy(payload, 4, 0, 8); 284 | 285 | return payload; 286 | } 287 | 288 | function Security$handshake(packet) { 289 | if(packet.encrypted) { 290 | throw new Error('[Security::Handshake] Received an illogical (encrypted) handshake packet.'); 291 | } 292 | 293 | if(this.m_client_security) { 294 | 295 | // If this object does not need a handshake 296 | if (this.m_security_flags.handshake == 0) { 297 | 298 | // Client should only accept it then 299 | if (packet.opcode == 0x9000) { 300 | 301 | if(this.m_accepted_handshake) { 302 | throw new Error('[Security::Handshake] Received an illogical handshake packet (duplicate 0x9000).'); 303 | } 304 | this.m_accepted_handshake = true; // Otherwise, all good here 305 | return; 306 | } 307 | // Client should not send any 0x5000s! 308 | else if (packet.opcode == 0x5000) { 309 | throw new Error('[Security::Handshake] Received an illogical handshake packet (0x5000 with no handshake).'); 310 | } 311 | // Programmer made a mistake in calling this function 312 | else { 313 | throw new Error('[Security::Handshake] Received an illogical handshake packet (programmer error).'); 314 | } 315 | } else { 316 | // Client accepts the handshake 317 | if (packet.opcode == 0x9000) { 318 | // Can't accept it before it's started! 319 | if (!this.m_started_handshake){ 320 | throw new Error('[Security::Handshake] Received an illogical handshake packet (out of order 0x9000).'); 321 | } 322 | if (this.m_accepted_handshake) { // Client error 323 | throw new Error('[Security::Handshake] Received an illogical handshake packet (duplicate 0x9000).'); 324 | } 325 | // Otherwise, all good here 326 | this.m_accepted_handshake = true; 327 | return; 328 | } 329 | // Client sends a handshake response 330 | else if (packet.opcode == 0x5000) { 331 | if (this.m_started_handshake) { // Client error 332 | throw new Error('[Security::Handshake] Received an illogical handshake packet (duplicate 0x5000).'); 333 | } 334 | this.m_started_handshake = true; 335 | } 336 | // Programmer made a mistake in calling this function 337 | else { 338 | throw new Error('[Security::Handshake] Received an illogical handshake packet (programmer error).'); 339 | } 340 | } 341 | 342 | this.m_value_B = packet.readDWord(); 343 | this.m_client_key.writeDoubleLE(packet.readQWord(), 0); 344 | 345 | this.m_value_K = this.gPowXmodP(this.m_value_p, this.m_value_x, this.m_value_B); 346 | 347 | this.key_array = this.keyTransformValue(this.m_value_A, this.m_value_B, this.m_value_K, helper.LOBYTE_(helper.LOWORD_(this.m_value_K)) & 0x03); 348 | this.m_blowfish.Initialize(this.key_array); 349 | 350 | this.m_client_key = this.m_blowfish.Decode(this.m_client_key, 0, 8); 351 | 352 | this.key_array = this.keyTransformValue(this.m_value_B, this.m_value_A, this.m_value_K, helper.LOBYTE_(helper.LOWORD_(this.m_value_B)) & 0x07); 353 | 354 | if(this.m_client_key.readDoubleLE(0) != this.key_array.readDoubleLE(0)) { 355 | throw new Error('[Security::Handshake] Client signature error.'); 356 | } 357 | 358 | this.key_array = this.keyTransformValue(this.m_value_A, this.m_value_B, this.m_value_K, helper.LOBYTE_(helper.LOWORD_(this.m_value_K)) & 0x03); 359 | this.m_blowfish.Initialize(this.key_array); 360 | 361 | this.m_challenge_key = this.keyTransformValue(this.m_value_A, this.m_value_B, this.m_value_K, helper.LOBYTE_(helper.LOWORD_(this.m_value_K)) & 0x07); 362 | this.m_challenge_key = this.m_blowfish.Encode(this.m_challenge_key, 0, 8).buff; 363 | 364 | this.m_handshake_blowfish_key = this.keyTransformValue(this.m_handshake_blowfish_key.readUInt32LE(0), this.m_handshake_blowfish_key.readUInt32LE(4), this.m_value_K, 0x3); 365 | 366 | this.m_blowfish.Initialize(this.m_handshake_blowfish_key); 367 | 368 | var tmp_flag, response, returnPackets; 369 | returnPackets = []; 370 | 371 | tmp_flag = this._fromSecurityFlags({ 372 | none: 0, 373 | blowfish: 0, 374 | security_bytes: 0, 375 | handshake: 0, 376 | handshake_response: 1, 377 | _6: 0, 378 | _7: 0, 379 | _8: 0, 380 | }); 381 | 382 | response = new PacketWriter(); 383 | response.writeByte(tmp_flag); 384 | response.writeQWord(this.m_challenge_key.readDoubleLE(0)); 385 | 386 | returnPackets.push({opcode: 0x5000, packet: response, encrypted: false}); 387 | 388 | return returnPackets; 389 | 390 | } else { 391 | if(packet.opcode != 0x5000) { 392 | throw new Error('[Security::Handshake] Received an illogical handshake packet (programmer error).'); 393 | } 394 | 395 | var flag, flags; 396 | flag = packet.readByte(); 397 | 398 | flags = this._toSecurityFlags(flag); 399 | 400 | if(this.m_security_flag == 0) { 401 | this.m_security_flag = flag; 402 | this.m_security_flags = flags; 403 | } 404 | 405 | if(flags.blowfish == 1) { 406 | this.m_initial_blowfish_key.writeDoubleLE(packet.readQWord(), 0); 407 | this.m_blowfish.Initialize(this.m_initial_blowfish_key); 408 | } 409 | if(flags.security_bytes == 1) { 410 | this.m_seed_count = packet.readDWord(); 411 | this.m_crc_seed = packet.readDWord(); 412 | this.setupCountByte(this.m_seed_count); 413 | } 414 | if(flags.handshake == 1) { 415 | this.m_handshake_blowfish_key.writeDoubleLE(packet.readQWord(), 0); 416 | this.m_value_g = packet.readDWord(); 417 | this.m_value_p = packet.readDWord(); 418 | this.m_value_A = packet.readDWord(); 419 | 420 | this.m_value_x = 0x33333333 & 0x7FFFFFFF; // "Random" 421 | 422 | this.m_value_B = this.gPowXmodP(this.m_value_p, this.m_value_x, this.m_value_g); 423 | this.m_value_K = this.gPowXmodP(this.m_value_p, this.m_value_x, this.m_value_A); 424 | 425 | this.key_array = this.keyTransformValue(this.m_value_A, this.m_value_B, this.m_value_K, helper.LOBYTE_(helper.LOWORD_(this.m_value_K)) & 0x03); 426 | 427 | this.m_client_key = this.keyTransformValue(this.m_value_B, this.m_value_A, this.m_value_K, helper.LOBYTE_(helper.LOWORD_(this.m_value_B)) & 0x07); 428 | 429 | this.m_blowfish.Initialize(this.key_array); 430 | this.m_client_key = this.m_blowfish.Encode(this.m_client_key, 0, 8).buff; 431 | } 432 | if(flags.handshake_response == 1) { 433 | var expected_challenge_key; 434 | 435 | this.m_challenge_key = packet.readQWord(); 436 | expected_challenge_key = this.keyTransformValue(this.m_value_A, this.m_value_B, this.m_value_K, helper.LOBYTE_(helper.LOWORD_(this.m_value_A)) & 0x07); 437 | expected_challenge_key = this.m_blowfish.Encode(expected_challenge_key, 0, 8).buff; 438 | expected_challenge_key = expected_challenge_key.readDoubleLE(0); 439 | if(this.m_challenge_key != expected_challenge_key) { 440 | throw new Error('[Security::Handshake] Server signature error.'); 441 | } 442 | 443 | this.m_handshake_blowfish_key = this.keyTransformValue(this.m_handshake_blowfish_key.readUInt32LE(0), this.m_handshake_blowfish_key.readUInt32LE(4), this.m_value_K, 0x3); 444 | this.m_blowfish.Initialize(this.m_handshake_blowfish_key); 445 | } 446 | 447 | //Generate outgoing packets 448 | if (flags.handshake == 1 && flags.handshake_response == 0) { 449 | var returnPackets, response; 450 | 451 | returnPackets = []; 452 | 453 | // Check to see if we already started a handshake 454 | if (this.m_started_handshake || this.m_accepted_handshake) { 455 | throw new Error('[Security::Handshake] Received an illogical handshake packet (duplicate 0x5000).'); 456 | } 457 | response = new PacketWriter(); 458 | response.writeDWord(this.m_value_B); 459 | response.writeQWord(this.m_client_key.readDoubleLE(0)); 460 | 461 | returnPackets.push({opcode: 0x5000, packet: response, encrypted: false}); 462 | 463 | this.m_started_handshake = true; 464 | 465 | return returnPackets; 466 | } else { 467 | var returnPackets, response1, response2; 468 | 469 | returnPackets = []; 470 | 471 | if(this.m_accepted_handshake) { 472 | throw new Error('[Security::Handshake] Received an illogical handshake packet (duplicate 0x5000).'); 473 | } 474 | 475 | //Handshake accept 476 | response1 = new PacketWriter(); 477 | returnPackets.push({opcode: 0x9000, packet: response1, encrypted: false}); 478 | 479 | // Identify 480 | response2 = new PacketWriter(); 481 | response2.writeString(this.m_identity_name); 482 | response2.writeByte(this.m_identity_flag); 483 | returnPackets.push({opcode: 0x2001, packet: response2, encrypted: true}); 484 | 485 | // Mark the handshake as accepted now 486 | this.m_started_handshake = true; 487 | this.m_accepted_handshake = true; 488 | 489 | return returnPackets; 490 | } 491 | } 492 | } 493 | 494 | function Security$formatPacket(opcode, data, encrypted) { 495 | var dataLength, packet, countByte, checkByte; 496 | dataLength = data.length; 497 | 498 | // Sanity check 499 | if(dataLength >= 0x8000) { 500 | throw new Error('[Security::FormatPacket] Payload is too large!'); 501 | } 502 | 503 | packet = new Buffer(dataLength + 6); 504 | 505 | // Add the packet header to the start of the data 506 | packet.writeUInt16LE(dataLength,0); 507 | packet.writeUInt16LE(opcode,2); 508 | packet.writeUInt16LE(0, 4); 509 | if(dataLength) { 510 | data.copy(packet, 6); 511 | } 512 | 513 | // Determine if we need to mark the packet size as encrypted 514 | if(encrypted && (this.m_security_flags.blowfish == 1 || (this.m_security_flags.security_bytes == 1 && this.m_security_flags.blowfish == 0))) { 515 | packet.writeUInt16LE((dataLength | 0x8000), 0); 516 | } 517 | 518 | // Only need to stamp bytes if this is a clientless object 519 | if(this.m_client_security == false && this.m_security_flags.security_bytes == 1) { 520 | 521 | countByte = this.generateCountByte(true); 522 | packet.writeUInt8(countByte, 4); 523 | 524 | checkByte = this.generateCheckByte(packet, 0, packet.length); 525 | packet.writeUInt8(checkByte, 5); 526 | } 527 | 528 | // If the packet should be physically encrypted, return an encrypted version of it 529 | if (encrypted && this.m_security_flags.blowfish == 1) { 530 | var encryptedData, realPacket; 531 | encryptedData = this.m_blowfish.Encode(packet, 2, dataLength + 4).buff; 532 | 533 | packet = new Buffer(encryptedData.length + 2); 534 | packet.writeUInt16LE((dataLength | 0x8000), 0); 535 | encryptedData.copy(packet, 2); 536 | } else { 537 | packet.writeUInt16LE(dataLength, 0); 538 | } 539 | 540 | return packet; 541 | } 542 | 543 | function Security$formatPacket_old(opcode, new_payload, length, encrypted) { 544 | var packet = new Buffer(length + 6); 545 | 546 | //Header 547 | packet.writeUInt16LE(length,0); 548 | packet.writeUInt16LE(opcode,2); 549 | packet.writeUInt16LE(0, 4); 550 | //End Header 551 | //Payload 552 | if (length != 0) { 553 | new_payload.copy(packet, 6); 554 | } 555 | //End Payload 556 | 557 | if (encrypted) 558 | { 559 | packet.writeUInt16LE((length | 0x8000), 0); 560 | } 561 | 562 | var countByte = this.generateCountByte(true); 563 | packet.writeUInt8(countByte, 4); 564 | 565 | var checkByte = this.generateCheckByte(packet, 0, length + 6); 566 | packet.writeUInt8(checkByte, 5); 567 | 568 | 569 | if (encrypted) 570 | { 571 | var encr = this.m_blowfish.Encode(packet, 2, length + 4); 572 | var realPacket = new Buffer(encr.size + 2); 573 | realPacket.writeUInt16LE((length | 0x8000), 0); 574 | encr.buff.copy(realPacket, 2); 575 | return realPacket; 576 | } 577 | 578 | return packet; 579 | } 580 | 581 | // Extended security 582 | 583 | function Security$_fromSecurityFlags(flags){ 584 | return (flags.none | flags.blowfish << 1 | flags.security_bytes << 2 | flags.handshake << 3 | flags.handshake_response << 4 | flags._6 << 5 | flags._7 << 6 | flags._8 << 7); 585 | } 586 | 587 | function Security$_toSecurityFlags(value){ 588 | flags = new Object(); 589 | flags.none = value & 1; 590 | value >>= 1; 591 | flags.blowfish = value & 1; 592 | value >>= 1; 593 | flags.security_bytes = value & 1; 594 | value >>= 1; 595 | flags.handshake = value & 1; 596 | value >>= 1; 597 | flags.handshake_response = value & 1; 598 | value >>= 1; 599 | flags._6 = value & 1; 600 | value >>= 1; 601 | flags._7 = value & 1; 602 | value >>= 1; 603 | flags._8 = value & 1; 604 | value >>= 1; 605 | return flags; 606 | } 607 | 608 | function Security$generateSecurity(blowfish, security_bytes, handshake) { 609 | var response, buffer; 610 | 611 | // Generate settings 612 | if(blowfish) { 613 | this.m_security_flags.none = 0; 614 | this.m_security_flags.blowfish = 1; 615 | } 616 | if(security_bytes) { 617 | this.m_security_flags.none = 0; 618 | this.m_security_flags.security_bytes = 1; 619 | } 620 | if(handshake) { 621 | this.m_security_flags.none = 0; 622 | this.m_security_flags.handshake = 1; 623 | } 624 | if(!blowfish && !security_bytes && !handshake) { 625 | this.m_security_flags.none = 1; 626 | } 627 | 628 | // Generate security 629 | this.m_security_flag = this._fromSecurityFlags(this.m_security_flags); 630 | this.m_client_security = true; 631 | 632 | response = new PacketWriter(); 633 | response.writeByte(this.m_security_flag); 634 | 635 | if(this.m_security_flags.blowfish == 1) { 636 | this.m_initial_blowfish_key.writeDoubleLE(0xdeadbeefcafebabe, 0); 637 | response.writeQWord(0xdeadbeefcafebabe); 638 | } 639 | if(this.m_security_flags.security_bytes == 1) { 640 | this.m_seed_count = 0x9ABFB3B6; 641 | this.setupCountByte(this.m_seed_count); 642 | this.m_crc_seed = 0x9ABFB3B6; 643 | 644 | response.writeDWord(this.m_seed_count); 645 | response.writeDWord(this.m_crc_seed); 646 | } 647 | if(this.m_security_flags.handshake == 1) { 648 | this.m_handshake_blowfish_key.writeDoubleLE(0xdeadbeefcafebabe, 0); 649 | this.m_value_x = 0x9ABFB3C6 & 0x7FFFFFFF; 650 | this.m_value_g = 0x9ABFB3D6 & 0x7FFFFFFF; 651 | this.m_value_p = 0x9ABFB3E6 & 0x7FFFFFFF; 652 | this.m_value_A = this.gPowXmodP(this.m_value_p, this.m_value_x, this.m_value_g); 653 | 654 | response.writeQWord(0xdeadbeefcafebabe); 655 | response.writeDWord(this.m_value_g); 656 | response.writeDWord(this.m_value_p); 657 | response.writeDWord(this.m_value_A); 658 | } 659 | 660 | return response; 661 | } -------------------------------------------------------------------------------- /blowfish/Blowfish.js: -------------------------------------------------------------------------------- 1 | var helper = require('../helper'); 2 | 3 | module.exports = Blowfish; 4 | 5 | function Blowfish() { 6 | this.PArray = [18]; 7 | this.SBoxes = [ 8 | [0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, 9 | 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 10 | 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, 11 | 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, 12 | 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 13 | 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, 14 | 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, 15 | 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 16 | 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, 17 | 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, 18 | 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 19 | 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, 20 | 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, 21 | 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 22 | 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, 23 | 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, 24 | 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 25 | 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, 26 | 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, 27 | 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 28 | 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, 29 | 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, 30 | 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 31 | 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, 32 | 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, 33 | 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 34 | 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, 35 | 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, 36 | 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 37 | 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, 38 | 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, 39 | 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a], 40 | [0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, 41 | 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 42 | 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, 43 | 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, 44 | 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 45 | 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, 46 | 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, 47 | 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 48 | 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, 49 | 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, 50 | 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 51 | 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, 52 | 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, 53 | 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 54 | 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, 55 | 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, 56 | 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 57 | 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, 58 | 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, 59 | 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 60 | 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, 61 | 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, 62 | 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 63 | 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, 64 | 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, 65 | 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 66 | 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, 67 | 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, 68 | 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 69 | 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, 70 | 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, 71 | 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7], 72 | [0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, 73 | 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 74 | 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, 75 | 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, 76 | 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 77 | 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, 78 | 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, 79 | 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 80 | 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, 81 | 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, 82 | 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 83 | 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, 84 | 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, 85 | 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 86 | 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, 87 | 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, 88 | 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 89 | 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, 90 | 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, 91 | 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 92 | 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, 93 | 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, 94 | 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 95 | 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, 96 | 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, 97 | 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 98 | 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, 99 | 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, 100 | 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 101 | 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, 102 | 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, 103 | 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0], 104 | [0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, 105 | 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 106 | 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, 107 | 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, 108 | 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 109 | 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, 110 | 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, 111 | 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 112 | 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, 113 | 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, 114 | 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 115 | 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, 116 | 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, 117 | 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 118 | 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, 119 | 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, 120 | 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 121 | 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, 122 | 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, 123 | 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 124 | 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, 125 | 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, 126 | 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 127 | 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, 128 | 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, 129 | 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 130 | 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, 131 | 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, 132 | 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 133 | 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, 134 | 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, 135 | 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6] 136 | ]; 137 | this.bf_P = [0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 138 | 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, 139 | 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, 140 | 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 141 | 0x9216d5d9, 0x8979fb1b]; 142 | this.bf_S = [ 143 | [0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, 144 | 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 145 | 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, 146 | 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, 147 | 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 148 | 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, 149 | 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, 150 | 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 151 | 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, 152 | 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, 153 | 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 154 | 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, 155 | 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, 156 | 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 157 | 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, 158 | 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, 159 | 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 160 | 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, 161 | 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, 162 | 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 163 | 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, 164 | 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, 165 | 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 166 | 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, 167 | 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, 168 | 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 169 | 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, 170 | 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, 171 | 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 172 | 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, 173 | 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, 174 | 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a], 175 | [0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, 176 | 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 177 | 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, 178 | 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, 179 | 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 180 | 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, 181 | 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, 182 | 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 183 | 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, 184 | 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, 185 | 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 186 | 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, 187 | 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, 188 | 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 189 | 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, 190 | 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, 191 | 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 192 | 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, 193 | 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, 194 | 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 195 | 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, 196 | 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, 197 | 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 198 | 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, 199 | 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, 200 | 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 201 | 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, 202 | 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, 203 | 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 204 | 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, 205 | 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, 206 | 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7], 207 | [0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, 208 | 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 209 | 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, 210 | 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, 211 | 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 212 | 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, 213 | 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, 214 | 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 215 | 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, 216 | 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, 217 | 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 218 | 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, 219 | 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, 220 | 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 221 | 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, 222 | 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, 223 | 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 224 | 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, 225 | 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, 226 | 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 227 | 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, 228 | 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, 229 | 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 230 | 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, 231 | 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, 232 | 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 233 | 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, 234 | 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, 235 | 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 236 | 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, 237 | 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, 238 | 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0], 239 | [0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, 240 | 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 241 | 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, 242 | 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, 243 | 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 244 | 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, 245 | 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, 246 | 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 247 | 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, 248 | 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, 249 | 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 250 | 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, 251 | 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, 252 | 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 253 | 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, 254 | 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, 255 | 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 256 | 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, 257 | 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, 258 | 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 259 | 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, 260 | 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, 261 | 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 262 | 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, 263 | 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, 264 | 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 265 | 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, 266 | 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, 267 | 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 268 | 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, 269 | 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, 270 | 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6] 271 | ]; 272 | 273 | } 274 | 275 | Blowfish.prototype = { 276 | S: function(x, i) { 277 | if(i < 0 || i > 3) 278 | { 279 | console.log("Blowfish::S invalid i "); 280 | } 281 | x >>>= (24 - (8 * i)); 282 | x &= 0xFF; 283 | 284 | return (this.SBoxes[i][x] >>> 0); 285 | }, 286 | 287 | bf_F: function(x) 288 | { 289 | return (((this.S(x, 0) + this.S(x, 1)) ^ this.S(x, 2)) + this.S(x, 3)); 290 | }, 291 | ROUND: function(a, b, n) 292 | { 293 | a ^= (((this.bf_F(b) >>> 0) ^ (this.PArray[n] >>> 0))); 294 | a = helper.toUInt32(a); 295 | return (a); 296 | }, 297 | Blowfish_encipher: function(xl, xr) 298 | { 299 | var Xl = xl; 300 | var Xr = xr; 301 | 302 | Xl ^= this.PArray[0]; 303 | Xl = helper.toUInt32(Xl); 304 | Xr = this.ROUND(Xr, Xl, 1); Xl = this.ROUND(Xl, Xr, 2); 305 | Xr = this.ROUND(Xr, Xl, 3); Xl = this.ROUND(Xl, Xr, 4); 306 | Xr = this.ROUND(Xr, Xl, 5); Xl = this.ROUND(Xl, Xr, 6); 307 | Xr = this.ROUND(Xr, Xl, 7); Xl = this.ROUND(Xl, Xr, 8); 308 | Xr = this.ROUND(Xr, Xl, 9); Xl = this.ROUND(Xl, Xr, 10); 309 | Xr = this.ROUND(Xr, Xl, 11); Xl = this.ROUND(Xl, Xr, 12); 310 | Xr = this.ROUND(Xr, Xl, 13); Xl = this.ROUND(Xl, Xr, 14); 311 | Xr = this.ROUND(Xr, Xl, 15); Xl = this.ROUND(Xl, Xr, 16); 312 | Xr ^= (this.PArray[17]); 313 | Xr = helper.toUInt32(Xr); 314 | 315 | xr = Xl; 316 | xl = Xr; 317 | 318 | var rtn = { xr: Xl, xl: Xr }; 319 | return rtn; 320 | }, 321 | Blowfish_decipher: function(xl, xr) 322 | { 323 | 324 | var Xl = xl; 325 | var Xr = xr; 326 | Xl ^= this.PArray[17]; 327 | Xl = helper.toUInt32(Xl); 328 | Xr = this.ROUND(Xr, Xl, 16); Xl = this.ROUND(Xl, Xr, 15); 329 | Xr = this.ROUND(Xr, Xl, 14); Xl = this.ROUND(Xl, Xr, 13); 330 | Xr = this.ROUND(Xr, Xl, 12); Xl = this.ROUND(Xl, Xr, 11); 331 | Xr = this.ROUND(Xr, Xl, 10); Xl = this.ROUND(Xl, Xr, 9); 332 | Xr = this.ROUND(Xr, Xl, 8); Xl = this.ROUND(Xl, Xr, 7); 333 | Xr = this.ROUND(Xr, Xl, 6); Xl = this.ROUND(Xl, Xr, 5); 334 | Xr = this.ROUND(Xr, Xl, 4); Xl = this.ROUND(Xl, Xr, 3); 335 | Xr = this.ROUND(Xr, Xl, 2); Xl = this.ROUND(Xl, Xr, 1); 336 | Xr ^= this.PArray[0]; 337 | Xr = helper.toUInt32(Xr); 338 | xl = Xr; 339 | xr = Xl; 340 | 341 | var rtn = { xr: xr , xl: xl }; 342 | return rtn; 343 | }, 344 | Initialize: function(key_ptr) 345 | { 346 | var i, j; 347 | var data, datal, datar; 348 | 349 | for(i = 0; i < 18;++i) 350 | { 351 | this.PArray[i] = this.bf_P[i]; 352 | } 353 | 354 | for(i = 0; i < 4; i++) 355 | { 356 | for(j = 0;j < 256; j++) 357 | { 358 | this.SBoxes[i][j] = this.bf_S[i][j]; 359 | } 360 | } 361 | var tmp = new Buffer(4); 362 | j = 0; 363 | for(i = 0; i < 16 + 2; ++i) 364 | { 365 | tmp[3] = key_ptr[j]; 366 | tmp[2] = key_ptr[(j + 1) % 8]; 367 | tmp[1] = key_ptr[(j + 2) % 8]; 368 | tmp[0] = key_ptr[(j + 3) % 8]; 369 | data = tmp.readUInt32LE(0, true); 370 | 371 | this.PArray[i] ^= data; 372 | this.PArray[i] = helper.toUInt32(this.PArray[i]); 373 | j = (j + 4) % 8; 374 | } 375 | 376 | datal = 0; 377 | datar = 0; 378 | 379 | for(i = 0; i < 16 + 2; i += 2) 380 | { 381 | var t = this.Blowfish_encipher(datal, datar); 382 | datal = t.xl; 383 | datar = t.xr; 384 | this.PArray[i] = datal; 385 | this.PArray[i + 1] = datar; 386 | } 387 | 388 | 389 | for(i = 0; i < 4;++i) 390 | { 391 | for(j = 0; j < 256; j += 2) 392 | { 393 | var t = this.Blowfish_encipher(datal, datar); 394 | datal = t.xl; 395 | datar = t.xr; 396 | this.SBoxes[i][j] = (t.xl); 397 | this.SBoxes[i][j + 1] = (t.xr); 398 | } 399 | } 400 | }, 401 | GetOutputLength: function(length) 402 | { 403 | return (length % 8) == 0 ? length : length + (8 - (length % 8)); 404 | }, 405 | Encode: function(stream, offset, length) 406 | { 407 | if(length == 0) 408 | { 409 | console.log("ERROR Lenght = 0!"); 410 | } 411 | var workspaceLength = this.GetOutputLength(length); //console.log("Lenght: %d Output Lenght: %d",length,workspaceLength); 412 | var workspace = new Buffer(workspaceLength); 413 | stream.copy(workspace, 0, offset); 414 | 415 | for(x = 0; x < workspaceLength; x += 8) 416 | { 417 | var l = workspace.readUInt32LE(x); 418 | var r = workspace.readUInt32LE(x + 4); 419 | var t = this.Blowfish_encipher(l, r); 420 | l = t.xl; 421 | r = t.xr; 422 | workspace.writeUInt32LE(l,x); 423 | workspace.writeUInt32LE(r,x + 4); 424 | } 425 | var obj = { size: workspaceLength, buff: workspace } 426 | return obj; 427 | //console.log(workspace); 428 | //return workspace; 429 | }, 430 | Decode: function(stream, offset, length) 431 | { 432 | if(length % 8 != 0 || length == 0) 433 | { 434 | console.log("ERROR invalid Lenght"); 435 | } 436 | var workspace = new Buffer(length); 437 | stream.copy(workspace, 0, offset); 438 | 439 | for(x = 0; x < length; x += 8) 440 | { 441 | var l = workspace.readUInt32LE(x); 442 | var r = workspace.readUInt32LE(x + 4); 443 | 444 | var t = this.Blowfish_decipher(l,r); 445 | l = t.xl; 446 | r = t.xr; 447 | 448 | workspace.writeUInt32LE(l,x); 449 | workspace.writeUInt32LE(r,x+4); 450 | } 451 | return workspace; 452 | } 453 | 454 | }; 455 | --------------------------------------------------------------------------------