diff --git a/doc/README.md b/doc/README.md index daca5a1..f87a864 100644 --- a/doc/README.md +++ b/doc/README.md @@ -73,7 +73,7 @@ Returns a `Client` instance and perform login. * accessToken : generated if a password is given * keepAlive : send keep alive packets : default to true * checkTimeoutInterval : default to `10*1000` (10s), check if keepalive received at that period, disconnect otherwise. - * version : 1.8 or 1.9 : default to 1.8 + * version : 1.8 or 1.9 or false (to auto-negotiate): default to 1.8 ## mc.Client(isServer,version) diff --git a/examples/client_auto/client_auto.js b/examples/client_auto/client_auto.js new file mode 100644 index 0000000..fdc586d --- /dev/null +++ b/examples/client_auto/client_auto.js @@ -0,0 +1,29 @@ +var mc = require('minecraft-protocol'); + +if(process.argv.length < 4 || process.argv.length > 6) { + console.log("Usage : node echo.js [] []"); + process.exit(1); +} + +var client = mc.createClient({version: false, + host: process.argv[2], + port: parseInt(process.argv[3]), + username: process.argv[4] ? process.argv[4] : "echo", + password: process.argv[5] +}); + +client.on('connect', function() { + console.info('connected'); +}); +client.on('disconnect', function(packet) { + console.log('disconnected: '+ packet.reason); +}); +client.on('chat', function(packet) { + var jsonMsg = JSON.parse(packet.message); + if(jsonMsg.translate == 'chat.type.announcement' || jsonMsg.translate == 'chat.type.text') { + var username = jsonMsg.with[0].text; + var msg = jsonMsg.with[1]; + if(username === client.username) return; + client.write('chat', {message: msg}); + } +}); diff --git a/examples/client_auto/package.json b/examples/client_auto/package.json new file mode 100644 index 0000000..56fcdf2 --- /dev/null +++ b/examples/client_auto/package.json @@ -0,0 +1,8 @@ +{ + "name": "node-minecraft-protocol-example", + "version": "0.0.0", + "private": true, + "dependencies": { + }, + "description": "A node-minecraft-protocol example" +} diff --git a/package.json b/package.json index 4fd7100..9c301c5 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ }, "dependencies": { "buffer-equal": "0.0.1", - "minecraft-data": "^0.16.1", + "minecraft-data": "^0.19.1", "prismarine-nbt": "0.1.0", "protodef": "0.2.5", "readable-stream": "^1.1.0", diff --git a/src/browser.js b/src/browser.js index f76c7c7..3e2d3ea 100644 --- a/src/browser.js +++ b/src/browser.js @@ -1,6 +1,6 @@ -var Client = require('./client'); -var Server = require('./server'); -var serializer = require("./transforms/serializer"); +const Client = require('./client'); +const Server = require('./server'); +const serializer = require("./transforms/serializer"); module.exports = { Client: Client, diff --git a/src/client.js b/src/client.js index fd31a2c..51b22d2 100644 --- a/src/client.js +++ b/src/client.js @@ -1,12 +1,12 @@ -var EventEmitter = require('events').EventEmitter; -var debug = require('./debug'); -var compression = require('./transforms/compression'); -var framing = require('./transforms/framing'); -var crypto = require('crypto'); -var states = require("./states"); +const EventEmitter = require('events').EventEmitter; +const debug = require('./debug'); +const compression = require('./transforms/compression'); +const framing = require('./transforms/framing'); +const crypto = require('crypto'); +const states = require("./states"); -var createSerializer=require("./transforms/serializer").createSerializer; -var createDeserializer=require("./transforms/serializer").createDeserializer; +const createSerializer=require("./transforms/serializer").createSerializer; +const createDeserializer=require("./transforms/serializer").createDeserializer; class Client extends EventEmitter { @@ -25,18 +25,17 @@ class Client extends EventEmitter this.decompressor=null; this.deserializer; this.isServer; - this.version; this.protocolState=states.HANDSHAKING; this.ended=true; this.latency=0; this.on('newListener', function(event, listener) { - var direction = this.isServer ? 'toServer' : 'toClient'; + const direction = this.isServer ? 'toServer' : 'toClient'; if(typeof this.packetsToParse[event] === "undefined") this.packetsToParse[event] = 1; else this.packetsToParse[event] += 1; }); this.on('removeListener', function(event, listener) { - var direction = this.isServer ? 'toServer' : 'toClient'; + const direction = this.isServer ? 'toServer' : 'toClient'; this.packetsToParse[event] -= 1; }); } @@ -54,9 +53,9 @@ class Client extends EventEmitter this.splitter.recognizeLegacyPing = state === states.HANDSHAKING; this.serializer.on('error', (e) => { - var parts=e.field.split("."); + const parts=e.field.split("."); parts.shift(); - var serializerDirection = !this.isServer ? 'toServer' : 'toClient'; + const serializerDirection = !this.isServer ? 'toServer' : 'toClient'; e.field = [this.protocolState, serializerDirection].concat(parts).join("."); e.message = `Serialization error for ${e.field} : ${e.message}`; this.emit('error',e); @@ -64,9 +63,9 @@ class Client extends EventEmitter this.deserializer.on('error', (e) => { - var parts=e.field.split("."); + const parts=e.field.split("."); parts.shift(); - var deserializerDirection = this.isServer ? 'toServer' : 'toClient'; + const deserializerDirection = this.isServer ? 'toServer' : 'toClient'; e.field = [this.protocolState, deserializerDirection].concat(parts).join("."); e.message = `Deserialization error for ${e.field} : ${e.message}`; this.emit('error',e); @@ -86,7 +85,7 @@ class Client extends EventEmitter } set state(newProperty) { - var oldProperty = this.protocolState; + const oldProperty = this.protocolState; this.protocolState = newProperty; if(!this.compressor) @@ -130,7 +129,7 @@ class Client extends EventEmitter this.ended = false; // TODO : A lot of other things needs to be done. - var endSocket = () => { + const endSocket = () => { if(this.ended) return; this.ended = true; this.socket.removeListener('close', endSocket); @@ -139,12 +138,12 @@ class Client extends EventEmitter this.emit('end', this._endReason); }; - var onFatalError = (err) => { + const onFatalError = (err) => { this.emit('error', err); endSocket(); }; - var onError = (err) => this.emit('error', err); + const onError = (err) => this.emit('error', err); this.socket = socket; @@ -219,7 +218,8 @@ class Client extends EventEmitter // TCP/IP-specific (not generic Stream) method for backwards-compatibility connect(port, host) { - var options = {port, host}; + const options = {port, host}; + if (!this.options) this.options = options; require('./client/tcp_dns')(this, options); options.connect(this); } diff --git a/src/client/autoVersion.js b/src/client/autoVersion.js new file mode 100644 index 0000000..4c45abc --- /dev/null +++ b/src/client/autoVersion.js @@ -0,0 +1,52 @@ +const ping = require('../ping'); +const debug = require('../debug'); +const states = require('../states'); +const assert = require('assert'); +const minecraft_data = require('minecraft-data'); + +module.exports = function(client, options) { + client.wait_connect = true; // don't let src/client/setProtocol proceed on socket 'connect' until 'connect_allowed' + debug('pinging',options.host); + const pingOptions = {host: options.host, port: options.port}; + // TODO: use 0xfe ping instead for better compatibility/performance? https://github.com/deathcap/node-minecraft-ping + ping(pingOptions, function(err, response) { + if (err) throw err; // hmm + debug('ping response',response); + // TODO: could also use ping pre-connect to save description, type, max players, etc. + const motd = response.description; + debug('Server description:',motd); // TODO: save + + // Pass server-reported version to protocol handler + // The version string is interpereted by https://github.com/PrismarineJS/node-minecraft-data + const minecraftVersion = response.version.name; // 1.8.9, 1.7.10 + const protocolVersion = response.version.protocol;// 47, 5 + + debug(`Server version: ${minecraftVersion}, protocol: ${protocolVersion}`); + // Note that versionName is a descriptive version stirng like '1.8.9' on vailla, but other + // servers add their own name (Spigot 1.8.8, Glowstone++ 1.8.9) so we cannot use it directly, + // even though it is in a format accepted by minecraft-data. Instead, translate the protocol. + // TODO: pre-Netty version support (uses overlapping version numbers, so would have to check versionName) + const versionInfos = minecraft_data.postNettyVersionsByProtocolVersion[protocolVersion]; + if (!versionInfos && versionInfos.length < 1) throw new Error(`unsupported/unknown protocol version: ${protocolVersion}, update minecraft-data`); + const versionInfo = versionInfos[0]; // use newest + options.version = versionInfo.minecraftVersion; + options.protocolVersion = protocolVersion; + + // Reinitialize client object with new version TODO: move out of its constructor? + client.version = versionInfo.majorVersion; + client.state = states.HANDSHAKING; + + if (response.modinfo && response.modinfo.type === 'FML') { + // Use the list of Forge mods from the server ping, so client will match server + const forgeMods = response.modinfo.modList; + debug('Using forgeMods:',forgeMods); + // TODO: https://github.com/PrismarineJS/node-minecraft-protocol/issues/114 + // https://github.com/PrismarineJS/node-minecraft-protocol/pull/326 + // TODO: modify client object to set forgeMods and enable forgeHandshake + throw new Error('FML/Forge not yet supported'); + } + // Finished configuring client object, let connection proceed + client.emit('connect_allowed'); + }); + return client; +}; diff --git a/src/client/caseCorrect.js b/src/client/caseCorrect.js index 2eb634a..e56941c 100644 --- a/src/client/caseCorrect.js +++ b/src/client/caseCorrect.js @@ -1,14 +1,14 @@ -var yggdrasil = require('yggdrasil')({}); -var UUID = require('uuid-1345'); +const yggdrasil = require('yggdrasil')({}); +const UUID = require('uuid-1345'); module.exports = function(client, options) { - var clientToken = options.clientToken || UUID.v4().toString(); + const clientToken = options.clientToken || UUID.v4().toString(); options.accessToken = null; options.haveCredentials = options.password != null || (clientToken != null && options.session != null); if(options.haveCredentials) { // make a request to get the case-correct username before connecting. - var cb = function(err, session) { + const cb = function(err, session) { if(err) { client.emit('error', err); } else { diff --git a/src/client/encrypt.js b/src/client/encrypt.js index 696ddfc..deb7993 100644 --- a/src/client/encrypt.js +++ b/src/client/encrypt.js @@ -1,7 +1,7 @@ -var crypto = require('crypto'); -var yggserver = require('yggdrasil').server({}); -var ursa=require("../ursa"); -var debug = require("../debug"); +const crypto = require('crypto'); +const yggserver = require('yggdrasil').server({}); +const ursa=require("../ursa"); +const debug = require("../debug"); module.exports = function(client, options) { client.once('encryption_begin', onEncryptionKeyRequest); @@ -40,9 +40,9 @@ module.exports = function(client, options) { } function sendEncryptionKeyResponse() { - var pubKey = mcPubKeyToURsa(packet.publicKey); - var encryptedSharedSecretBuffer = pubKey.encrypt(sharedSecret, undefined, undefined, ursa.RSA_PKCS1_PADDING); - var encryptedVerifyTokenBuffer = pubKey.encrypt(packet.verifyToken, undefined, undefined, ursa.RSA_PKCS1_PADDING); + const pubKey = mcPubKeyToURsa(packet.publicKey); + const encryptedSharedSecretBuffer = pubKey.encrypt(sharedSecret, undefined, undefined, ursa.RSA_PKCS1_PADDING); + const encryptedVerifyTokenBuffer = pubKey.encrypt(packet.verifyToken, undefined, undefined, ursa.RSA_PKCS1_PADDING); client.write('encryption_begin', { sharedSecret: encryptedSharedSecretBuffer, verifyToken: encryptedVerifyTokenBuffer @@ -54,9 +54,9 @@ module.exports = function(client, options) { }; function mcPubKeyToURsa(mcPubKeyBuffer) { - var pem = "-----BEGIN PUBLIC KEY-----\n"; - var base64PubKey = mcPubKeyBuffer.toString('base64'); - var maxLineLength = 65; + let pem = "-----BEGIN PUBLIC KEY-----\n"; + let base64PubKey = mcPubKeyBuffer.toString('base64'); + const maxLineLength = 65; while(base64PubKey.length > 0) { pem += base64PubKey.substring(0, maxLineLength) + "\n"; base64PubKey = base64PubKey.substring(maxLineLength); diff --git a/src/client/keepalive.js b/src/client/keepalive.js index 3fc817b..fae0017 100644 --- a/src/client/keepalive.js +++ b/src/client/keepalive.js @@ -1,12 +1,12 @@ module.exports = function(client, options) { - var keepAlive = options.keepAlive == null ? true : options.keepAlive; + const keepAlive = options.keepAlive == null ? true : options.keepAlive; if (!keepAlive) return; - var checkTimeoutInterval = options.checkTimeoutInterval || 10 * 1000; + const checkTimeoutInterval = options.checkTimeoutInterval || 10 * 1000; client.on('keep_alive', onKeepAlive); - var timeout = null; + let timeout = null; function onKeepAlive(packet) { if (timeout) diff --git a/src/client/play.js b/src/client/play.js index ebc491e..b01fe29 100644 --- a/src/client/play.js +++ b/src/client/play.js @@ -1,4 +1,4 @@ -var states = require("../states"); +const states = require("../states"); module.exports = function(client, options) { client.once('success', onLogin); diff --git a/src/client/setProtocol.js b/src/client/setProtocol.js index 69ed83d..eb2c480 100644 --- a/src/client/setProtocol.js +++ b/src/client/setProtocol.js @@ -1,24 +1,29 @@ - -var states = require("../states"); +const states = require("../states"); module.exports = function(client, options) { client.on('connect', onConnect); function onConnect() { - var taggedHost = options.host; + let taggedHost = options.host; if (options.tagHost) taggedHost += options.tagHost; - client.write('set_protocol', { - protocolVersion: options.protocolVersion, - serverHost: taggedHost, - serverPort: options.port, - nextState: 2 - }); - client.state = states.LOGIN; - client.write('login_start', { - username: client.username - }); + if (client.wait_connect) { + client.on('connect_allowed', next); + } else { + next(); + } + + function next() { + client.write('set_protocol', { + protocolVersion: options.protocolVersion, + serverHost: taggedHost, + serverPort: options.port, + nextState: 2 + }); + client.state = states.LOGIN; + client.write('login_start', { + username: client.username + }); + } } - - -} +}; diff --git a/src/client/tcp_dns.js b/src/client/tcp_dns.js index 579cb80..f0b5c33 100644 --- a/src/client/tcp_dns.js +++ b/src/client/tcp_dns.js @@ -1,5 +1,5 @@ -var net = require('net'); -var dns = require('dns'); +const net = require('net'); +const dns = require('dns'); module.exports = function(client, options) { options.port = options.port || 25565; diff --git a/src/createClient.js b/src/createClient.js index bdce948..c1dc53e 100644 --- a/src/createClient.js +++ b/src/createClient.js @@ -1,14 +1,15 @@ -var Client = require('./client'); -var assert = require('assert'); +const Client = require('./client'); +const assert = require('assert'); -var encrypt = require('./client/encrypt'); -var keepalive = require('./client/keepalive'); -var compress = require('./client/compress'); -var caseCorrect = require('./client/caseCorrect'); -var setProtocol = require('./client/setProtocol'); -var play = require('./client/play'); -var tcp_dns = require('./client/tcp_dns'); -var forgeHandshake = require('./client/forgeHandshake'); +const encrypt = require('./client/encrypt'); +const keepalive = require('./client/keepalive'); +const compress = require('./client/compress'); +const caseCorrect = require('./client/caseCorrect'); +const setProtocol = require('./client/setProtocol'); +const play = require('./client/play'); +const tcp_dns = require('./client/tcp_dns'); +const autoVersion = require('./client/autoVersion'); +const forgeHandshake = require('./client/forgeHandshake'); module.exports=createClient; @@ -16,22 +17,25 @@ function createClient(options) { assert.ok(options, "options is required"); assert.ok(options.username, "username is required"); - var optVersion = options.version || require("./version").defaultVersion; - var mcData=require("minecraft-data")(optVersion); - var version = mcData.version; + // TODO: avoid setting default version if autoVersion is enabled + const optVersion = options.version || require("./version").defaultVersion; + const mcData=require("minecraft-data")(optVersion); + if (!mcData) throw new Error(`unsupported protocol version: ${optVersion}`); + const version = mcData.version; options.majorVersion = version.majorVersion; options.protocolVersion = version.version; - var client = new Client(false, options.majorVersion); + const client = new Client(false, options.majorVersion); tcp_dns(client, options); if (options.forgeMods) forgeHandshake(client, options); + caseCorrect(client, options); + if (options.version === false) autoVersion(client, options); setProtocol(client, options); keepalive(client, options); encrypt(client, options); play(client, options); compress(client, options); - caseCorrect(client, options); return client; } diff --git a/src/createServer.js b/src/createServer.js index 9a4b71d..aaf0dd6 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -1,38 +1,38 @@ -var ursa=require("./ursa"); -var crypto = require('crypto'); -var yggserver = require('yggdrasil').server({}); -var states = require("./states"); -var bufferEqual = require('buffer-equal'); -var Server = require('./server'); -var UUID = require('uuid-1345'); -var endianToggle = require('endian-toggle'); +const ursa=require("./ursa"); +const crypto = require('crypto'); +const yggserver = require('yggdrasil').server({}); +const states = require("./states"); +const bufferEqual = require('buffer-equal'); +const Server = require('./server'); +const UUID = require('uuid-1345'); +const endianToggle = require('endian-toggle'); module.exports=createServer; function createServer(options) { options = options || {}; - var port = options.port != null ? + const port = options.port != null ? options.port : options['server-port'] != null ? options['server-port'] : 25565; - var host = options.host || '0.0.0.0'; - var kickTimeout = options.kickTimeout || 10 * 1000; - var checkTimeoutInterval = options.checkTimeoutInterval || 4 * 1000; - var onlineMode = options['online-mode'] == null ? true : options['online-mode']; + const host = options.host || '0.0.0.0'; + const kickTimeout = options.kickTimeout || 10 * 1000; + const checkTimeoutInterval = options.checkTimeoutInterval || 4 * 1000; + const onlineMode = options['online-mode'] == null ? true : options['online-mode']; // a function receiving the default status object and the client // and returning a modified response object. - var beforePing = options.beforePing || null; + const beforePing = options.beforePing || null; - var enableKeepAlive = options.keepAlive == null ? true : options.keepAlive; + const enableKeepAlive = options.keepAlive == null ? true : options.keepAlive; - var optVersion = options.version || require("./version").defaultVersion; - var mcData=require("minecraft-data")(optVersion); - var version = mcData.version; + const optVersion = options.version || require("./version").defaultVersion; + const mcData=require("minecraft-data")(optVersion); + const version = mcData.version; - var serverKey = ursa.generatePrivateKey(1024); + const serverKey = ursa.generatePrivateKey(1024); - var server = new Server(version.majorVersion); + const server = new Server(version.majorVersion); server.motd = options.motd || "A Minecraft server"; server.maxPlayers = options['max-players'] || 20; server.playerCount = 0; @@ -44,16 +44,16 @@ function createServer(options) { client.once('legacy_server_list_ping', onLegacyPing); client.on('end', onEnd); - var keepAlive = false; - var loggedIn = false; - var lastKeepAlive = null; + let keepAlive = false; + let loggedIn = false; + let lastKeepAlive = null; - var keepAliveTimer = null; - var loginKickTimer = setTimeout(kickForNotLoggingIn, kickTimeout); + let keepAliveTimer = null; + let loginKickTimer = setTimeout(kickForNotLoggingIn, kickTimeout); - var serverId; - - var sendKeepAliveTime; + let serverId; + + let sendKeepAliveTime; function kickForNotLoggingIn() { client.end('LoginTimeout'); @@ -64,7 +64,7 @@ function createServer(options) { return; // check if the last keepAlive was too long ago (kickTimeout) - var elapsed = new Date() - lastKeepAlive; + const elapsed = new Date() - lastKeepAlive; if(elapsed > kickTimeout) { client.end('KeepAliveTimeout'); return; @@ -93,7 +93,7 @@ function createServer(options) { } function onPing() { - var response = { + const response = { "version": { "name": version.minecraftVersion, "protocol": version.version @@ -130,7 +130,7 @@ function createServer(options) { function onLegacyPing(packet) { if (packet.payload === 1) { - var pingVersion = 1; + const pingVersion = 1; sendPingResponse('\xa7' + [pingVersion, version.version, version.minecraftVersion, server.motd, server.playerCount.toString(), server.maxPlayers.toString()].join('\0')); } else { @@ -143,13 +143,13 @@ function createServer(options) { return endianToggle(new Buffer(s, 'utf16le'), 16); } - var responseBuffer = utf16be(responseString); + const responseBuffer = utf16be(responseString); - var length = responseString.length; // UCS2 characters, not bytes - var lengthBuffer = new Buffer(2); + const length = responseString.length; // UCS2 characters, not bytes + const lengthBuffer = new Buffer(2); lengthBuffer.writeUInt16BE(length); - var raw = Buffer.concat([new Buffer('ff', 'hex'), lengthBuffer, responseBuffer]); + const raw = Buffer.concat([new Buffer('ff', 'hex'), lengthBuffer, responseBuffer]); //client.writeRaw(raw); // not raw enough, it includes length client.socket.write(raw); @@ -159,14 +159,14 @@ function createServer(options) { function onLogin(packet) { client.username = packet.username; - var isException = !!server.onlineModeExceptions[client.username.toLowerCase()]; - var needToVerify = (onlineMode && !isException) || (!onlineMode && isException); + const isException = !!server.onlineModeExceptions[client.username.toLowerCase()]; + const needToVerify = (onlineMode && !isException) || (!onlineMode && isException); if(needToVerify) { serverId = crypto.randomBytes(4).toString('hex'); client.verifyToken = crypto.randomBytes(4); - var publicKeyStrArr = serverKey.toPublicPem("utf8").split("\n"); - var publicKeyStr = ""; - for(var i = 1; i < publicKeyStrArr.length - 2; i++) { + const publicKeyStrArr = serverKey.toPublicPem("utf8").split("\n"); + let publicKeyStr = ""; + for(let i = 1; i < publicKeyStrArr.length - 2; i++) { publicKeyStr += publicKeyStrArr[i] } client.publicKey = new Buffer(publicKeyStr, 'base64'); @@ -197,22 +197,23 @@ function createServer(options) { } function onEncryptionKeyResponse(packet) { + let sharedSecret; try { - var verifyToken = serverKey.decrypt(packet.verifyToken, undefined, undefined, ursa.RSA_PKCS1_PADDING); + const verifyToken = serverKey.decrypt(packet.verifyToken, undefined, undefined, ursa.RSA_PKCS1_PADDING); if(!bufferEqual(client.verifyToken, verifyToken)) { client.end('DidNotEncryptVerifyTokenProperly'); return; } - var sharedSecret = serverKey.decrypt(packet.sharedSecret, undefined, undefined, ursa.RSA_PKCS1_PADDING); + sharedSecret = serverKey.decrypt(packet.sharedSecret, undefined, undefined, ursa.RSA_PKCS1_PADDING); } catch(e) { client.end('DidNotEncryptVerifyTokenProperly'); return; } client.setEncryption(sharedSecret); - var isException = !!server.onlineModeExceptions[client.username.toLowerCase()]; - var needToVerify = (onlineMode && !isException) || (!onlineMode && isException); - var nextStep = needToVerify ? verifyUsername : loginClient; + const isException = !!server.onlineModeExceptions[client.username.toLowerCase()]; + const needToVerify = (onlineMode && !isException) || (!onlineMode && isException); + const nextStep = needToVerify ? verifyUsername : loginClient; nextStep(); function verifyUsername() { @@ -234,9 +235,9 @@ function createServer(options) { // https://github.com/openjdk-mirror/jdk7u-jdk/blob/f4d80957e89a19a29bb9f9807d2a28351ed7f7df/src/share/classes/java/util/UUID.java#L163 function javaUUID(s) { - var hash = crypto.createHash("md5"); + const hash = crypto.createHash("md5"); hash.update(s, 'utf8'); - var buffer = hash.digest(); + const buffer = hash.digest(); buffer[6] = (buffer[6] & 0x0f) | 0x30; buffer[8] = (buffer[8] & 0x3f) | 0x80; return buffer; @@ -248,7 +249,7 @@ function createServer(options) { } function loginClient() { - var isException = !!server.onlineModeExceptions[client.username.toLowerCase()]; + const isException = !!server.onlineModeExceptions[client.username.toLowerCase()]; if(onlineMode == false || isException) { client.uuid = nameToMcOfflineUUID(client.username); } diff --git a/src/datatypes/minecraft.js b/src/datatypes/minecraft.js index 956212f..047820c 100644 --- a/src/datatypes/minecraft.js +++ b/src/datatypes/minecraft.js @@ -1,5 +1,5 @@ -var nbt = require('prismarine-nbt'); -var UUID = require('uuid-1345'); +const nbt = require('prismarine-nbt'); +const UUID = require('uuid-1345'); module.exports = { 'UUID': [readUUID, writeUUID, 16], @@ -17,7 +17,7 @@ function readUUID(buffer, offset) { } function writeUUID(value, buffer, offset) { - var buf=UUID.parse(value); + const buf=UUID.parse(value); buf.copy(buffer,offset); return offset + 16; } @@ -71,9 +71,9 @@ function sizeOfRestBuffer(value) { } function readEntityMetadata(buffer, offset, {type,endVal}) { - var cursor = offset; - var metadata = []; - var item; + let cursor = offset; + const metadata = []; + let item; while(true) { item = buffer.readUInt8(cursor); if(item === endVal) { @@ -82,14 +82,14 @@ function readEntityMetadata(buffer, offset, {type,endVal}) { size: cursor + 1 - offset }; } - var results = this.read(buffer, cursor, type, {}); + const results = this.read(buffer, cursor, type, {}); metadata.push(results.value); cursor += results.size; } } function writeEntityMetadata(value, buffer, offset, {type,endVal}) { - var self = this; + const self = this; value.forEach(function(item) { offset = self.write(item, buffer, offset, type, {}); }); @@ -98,8 +98,8 @@ function writeEntityMetadata(value, buffer, offset, {type,endVal}) { } function sizeOfEntityMetadata(value, {type}) { - var size = 1; - for(var i = 0; i < value.length; ++i) { + let size = 1; + for(let i = 0; i < value.length; ++i) { size += this.sizeOf(value[i], type, {}); } return size; diff --git a/src/debug.js b/src/debug.js index 6b8e326..7ea4f99 100644 --- a/src/debug.js +++ b/src/debug.js @@ -1,8 +1,8 @@ -var util = require('util'); +const util = require('util'); -var debug; +let debug; if(process.env.NODE_DEBUG && /(minecraft-protocol|mc-proto)/.test(process.env.NODE_DEBUG)) { - var pid = process.pid; + const pid = process.pid; debug = function(x) { // if console is not set up yet, then skip this. if(!console.error) diff --git a/src/index.js b/src/index.js index 8d90027..024ae3e 100644 --- a/src/index.js +++ b/src/index.js @@ -1,8 +1,8 @@ -var Client = require('./client'); -var Server = require('./server'); -var serializer = require("./transforms/serializer"); -var createClient = require("./createClient"); -var createServer = require("./createServer"); +const Client = require('./client'); +const Server = require('./server'); +const serializer = require("./transforms/serializer"); +const createClient = require("./createClient"); +const createServer = require("./createServer"); module.exports = { createClient: createClient, diff --git a/src/ping.js b/src/ping.js index 4a58353..5ec3ab7 100644 --- a/src/ping.js +++ b/src/ping.js @@ -1,27 +1,27 @@ -var net = require('net'); -var Client = require('./client'); -var states = require("./states"); -var tcp_dns = require('./client/tcp_dns'); +const net = require('net'); +const Client = require('./client'); +const states = require("./states"); +const tcp_dns = require('./client/tcp_dns'); module.exports = ping; function ping(options, cb) { options.host = options.host || 'localhost'; options.port = options.port || 25565; - var optVersion = options.version || require("./version").defaultVersion; - var mcData=require("minecraft-data")(optVersion); - var version = mcData.version; + const optVersion = options.version || require("./version").defaultVersion; + const mcData=require("minecraft-data")(optVersion); + const version = mcData.version; options.majorVersion = version.majorVersion; options.protocolVersion = version.version; - var client = new Client(false,options.majorVersion); + const client = new Client(false,options.majorVersion); client.on('error', function(err) { cb(err); }); client.once('server_info', function(packet) { - var data = JSON.parse(packet.response); - var start = Date.now(); + const data = JSON.parse(packet.response); + const start = Date.now(); client.once('ping', function(packet) { data.latency = Date.now() - start; cb(null, data); diff --git a/src/server.js b/src/server.js index d604b9f..daab15e 100644 --- a/src/server.js +++ b/src/server.js @@ -1,7 +1,7 @@ -var net = require('net'); -var EventEmitter = require('events').EventEmitter; -var Client = require('./client'); -var states = require("./states"); +const net = require('net'); +const EventEmitter = require('events').EventEmitter; +const Client = require('./client'); +const states = require("./states"); class Server extends EventEmitter { @@ -15,11 +15,11 @@ class Server extends EventEmitter } listen(port, host) { - var self = this; - var nextId = 0; + const self = this; + let nextId = 0; self.socketServer = net.createServer(); self.socketServer.on('connection', socket => { - var client = new Client(true,this.version); + const client = new Client(true,this.version); client._end = client.end; client.end = function end(endReason) { endReason='{"text":"'+endReason+'"}'; @@ -51,13 +51,10 @@ class Server extends EventEmitter } close() { - var client; - for(var clientId in this.clients) { - if(!this.clients.hasOwnProperty(clientId)) continue; - - client = this.clients[clientId]; + Object.keys(this.clients).forEach(clientId => { + const client = this.clients[clientId]; client.end('ServerShutdown'); - } + }); this.socketServer.close(); } } diff --git a/src/states.js b/src/states.js index a50cafc..56f4de5 100644 --- a/src/states.js +++ b/src/states.js @@ -1,4 +1,4 @@ -var states = { +const states = { "HANDSHAKING": "handshaking", "STATUS": "status", "LOGIN": "login", diff --git a/src/transforms/compression.js b/src/transforms/compression.js index 17e89b3..8275033 100644 --- a/src/transforms/compression.js +++ b/src/transforms/compression.js @@ -1,6 +1,6 @@ -var [readVarInt, writeVarInt, sizeOfVarInt] = require("protodef").types.varint; -var zlib = require("zlib"); -var Transform = require("readable-stream").Transform; +const [readVarInt, writeVarInt, sizeOfVarInt] = require("protodef").types.varint; +const zlib = require("zlib"); +const Transform = require("readable-stream").Transform; module.exports.createCompressor = function(threshold) { return new Compressor(threshold); @@ -22,8 +22,8 @@ class Compressor extends Transform { zlib.deflate(chunk, (err, newChunk) => { if (err) return cb(err); - var buf = new Buffer(sizeOfVarInt(chunk.length) + newChunk.length); - var offset = writeVarInt(chunk.length, buf, 0); + const buf = new Buffer(sizeOfVarInt(chunk.length) + newChunk.length); + const offset = writeVarInt(chunk.length, buf, 0); newChunk.copy(buf, offset); this.push(buf); return cb(); @@ -31,8 +31,8 @@ class Compressor extends Transform { } else { - var buf = new Buffer(sizeOfVarInt(0) + chunk.length); - var offset = writeVarInt(0, buf, 0); + const buf = new Buffer(sizeOfVarInt(0) + chunk.length); + const offset = writeVarInt(0, buf, 0); chunk.copy(buf, offset); this.push(buf); return cb(); @@ -47,7 +47,7 @@ class Decompressor extends Transform { } _transform(chunk, enc, cb) { - var { size, value, error } = readVarInt(chunk, 0); + const { size, value, error } = readVarInt(chunk, 0); if (error) return cb(error); if (value === 0) diff --git a/src/transforms/framing.js b/src/transforms/framing.js index 48e67c2..9b73a0d 100644 --- a/src/transforms/framing.js +++ b/src/transforms/framing.js @@ -1,5 +1,5 @@ -var [readVarInt, writeVarInt, sizeOfVarInt] = require("protodef").types.varint; -var Transform = require("readable-stream").Transform; +const [readVarInt, writeVarInt, sizeOfVarInt] = require("protodef").types.varint; +const Transform = require("readable-stream").Transform; module.exports.createSplitter = function() { return new Splitter(); @@ -16,7 +16,7 @@ class Framer extends Transform { _transform(chunk, enc, cb) { const varIntSize=sizeOfVarInt(chunk.length); - var buffer = new Buffer(varIntSize + chunk.length); + const buffer = new Buffer(varIntSize + chunk.length); writeVarInt(chunk.length, buffer, 0); chunk.copy(buffer, varIntSize); this.push(buffer); @@ -38,17 +38,17 @@ class Splitter extends Transform { if (this.recognizeLegacyPing && this.buffer[0] === LEGACY_PING_PACKET_ID) { // legacy_server_list_ping packet follows a different protocol format // prefix the encoded varint packet id for the deserializer - var header = new Buffer(sizeOfVarInt(LEGACY_PING_PACKET_ID)); + const header = new Buffer(sizeOfVarInt(LEGACY_PING_PACKET_ID)); writeVarInt(LEGACY_PING_PACKET_ID, header, 0); - var payload = this.buffer.slice(1); // remove 0xfe packet id + let payload = this.buffer.slice(1); // remove 0xfe packet id if (payload.length === 0) payload = new Buffer('\0'); // TODO: update minecraft-data to recognize a lone 0xfe, https://github.com/PrismarineJS/minecraft-data/issues/95 this.push(Buffer.concat([header, payload])); return cb(); } - var offset = 0; + let offset = 0; - var { value, size, error } = readVarInt(this.buffer, offset) || { error: "Not enough data" }; + let { value, size, error } = readVarInt(this.buffer, offset) || { error: "Not enough data" }; while (!error && this.buffer.length >= offset + size + value) { this.push(this.buffer.slice(offset + size, offset + size + value)); diff --git a/src/transforms/serializer.js b/src/transforms/serializer.js index 76852b4..23cc982 100644 --- a/src/transforms/serializer.js +++ b/src/transforms/serializer.js @@ -1,13 +1,13 @@ -var ProtoDef = require("protodef").ProtoDef; -var Serializer = require("protodef").Serializer; -var Parser = require("protodef").Parser; +const ProtoDef = require("protodef").ProtoDef; +const Serializer = require("protodef").Serializer; +const Parser = require("protodef").Parser; -var minecraft = require("../datatypes/minecraft"); -var states = require("../states"); +const minecraft = require("../datatypes/minecraft"); +const states = require("../states"); function createProtocol(types,packets) { - var proto = new ProtoDef(); + const proto = new ProtoDef(); proto.addType("string",["pstring",{ countType:"varint" }]); @@ -38,20 +38,20 @@ function createProtocol(types,packets) function createSerializer({ state = states.HANDSHAKING, isServer = false , version} = {}) { - var mcData=require("minecraft-data")(version); - var direction = !isServer ? 'toServer' : 'toClient'; - var packets = mcData.protocol.states[state][direction]; - var proto=createProtocol(mcData.protocol.types,packets); + const mcData=require("minecraft-data")(version); + const direction = !isServer ? 'toServer' : 'toClient'; + const packets = mcData.protocol.states[state][direction]; + const proto=createProtocol(mcData.protocol.types,packets); return new Serializer(proto,"packet"); } function createDeserializer({ state = states.HANDSHAKING, isServer = false, packetsToParse = {"packet": true}, version } = {}) { - var mcData=require("minecraft-data")(version); - var direction = isServer ? "toServer" : "toClient"; - var packets = mcData.protocol.states[state][direction]; - var proto=createProtocol(mcData.protocol.types,packets); + const mcData=require("minecraft-data")(version); + const direction = isServer ? "toServer" : "toClient"; + const packets = mcData.protocol.states[state][direction]; + const proto=createProtocol(mcData.protocol.types,packets); return new Parser(proto,"packet"); } diff --git a/src/ursa.js b/src/ursa.js index fe35730..1ca32d5 100644 --- a/src/ursa.js +++ b/src/ursa.js @@ -1,4 +1,4 @@ -var ursa; +let ursa; try { ursa = require("ursa"); } catch(e) {