Skip to content

Commit

Permalink
Merge branch 'dynxver'
Browse files Browse the repository at this point in the history
PrismarineJS/node-minecraft-protocol#331 Add dynamic cross-protocol support
  • Loading branch information
deathcap committed Feb 1, 2016
2 parents b817dd9 + ddcca01 commit ba89e24
Show file tree
Hide file tree
Showing 15 changed files with 143 additions and 21 deletions.
2 changes: 1 addition & 1 deletion doc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
29 changes: 29 additions & 0 deletions examples/client_auto/client_auto.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
var mc = require('minecraft-protocol');

if(process.argv.length < 4 || process.argv.length > 6) {
console.log("Usage : node echo.js <host> <port> [<name>] [<password>]");
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});
}
});
8 changes: 8 additions & 0 deletions examples/client_auto/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "node-minecraft-protocol-example",
"version": "0.0.0",
"private": true,
"dependencies": {
},
"description": "A node-minecraft-protocol example"
}
2 changes: 1 addition & 1 deletion src/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ class Client extends EventEmitter
this.decompressor=null;
this.deserializer;
this.isServer;
this.version;
this.protocolState=states.HANDSHAKING;
this.ended=true;
this.latency=0;
Expand Down Expand Up @@ -219,6 +218,7 @@ class Client extends EventEmitter
// TCP/IP-specific (not generic Stream) method for backwards-compatibility
connect(port, host) {
var options = {port, host};
if (!this.options) this.options = options;
require('./client/tcp_dns')(this, options);
options.connect(this);
}
Expand Down
67 changes: 67 additions & 0 deletions src/client/autoVersion.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
'use strict';

var ping = require('../ping');
var debug = require('../debug');
var states = require('../states');
var assert = require('assert');
var minecraft_data = require('minecraft-data');

// Get the minecraft-data version string for a protocol version
// TODO: add to node-minecraft-data index (protocol to newest release, if multiple)
function protocolVersion2MinecraftVersion(n) {
var usesNetty = true; // for now, only Netty protocols are supported TODO: pre-Netty (beware, colliding protocol version numbers)
for (var i = 0; i < minecraft_data.versions.length; ++i) {
var version = minecraft_data.versions[i];
if (version.version === n && version.usesNetty === usesNetty) {
return [version.minecraftVersion, version.majorVersion];
}
}

throw new Error(`unsupported/unknown protocol version: ${n}, update minecraft-data`);
}

module.exports = function(client) {
var options = client.options;

options.wait_connect = true; // don't let src/client/setProtocol proceed on socket 'connect' until 'connect_allowed'
debug('pinging',options.host);
var 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.
var 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
var minecraftVersion = response.version.name; // 1.8.9, 1.7.10
var 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.
var [minecraftVersion, majorVersion] = protocolVersion2MinecraftVersion(protocolVersion);
client.options.version = minecraftVersion;
client.options.protocolVersion = protocolVersion;

// Reinitialize client object with new version TODO: move out of its constructor?
client.version = 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
var 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;
}
3 changes: 2 additions & 1 deletion src/client/caseCorrect.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
var yggdrasil = require('yggdrasil')({});
var UUID = require('uuid-1345');

module.exports = function(client, options) {
module.exports = function(client) {
var options = client.options;
var clientToken = options.clientToken || UUID.v4().toString();
options.accessToken = null;
options.haveCredentials = options.password != null || (clientToken != null && options.session != null);
Expand Down
2 changes: 1 addition & 1 deletion src/client/compress.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module.exports = function(client, options) {
module.exports = function(client) {
client.once("compress", onCompressionRequest);
client.on("set_compression", onCompressionRequest);

Expand Down
3 changes: 2 additions & 1 deletion src/client/encrypt.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ var yggserver = require('yggdrasil').server({});
var ursa=require("../ursa");
var debug = require("../debug");

module.exports = function(client, options) {
module.exports = function(client) {
var options = client.options;
client.once('encryption_begin', onEncryptionKeyRequest);

function onEncryptionKeyRequest(packet) {
Expand Down
3 changes: 2 additions & 1 deletion src/client/forgeHandshake.js
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,8 @@ function fmlHandshakeStep(client, data, options)
}
}

module.exports = function(client, options) {
module.exports = function(client) {
var options = client.options;
options.tagHost = '\0FML\0'; // passed to src/client/setProtocol.js, signifies client supports FML/Forge

client.on('custom_payload', function(packet) {
Expand Down
3 changes: 2 additions & 1 deletion src/client/keepalive.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
module.exports = function(client, options) {
module.exports = function(client) {
var options = client.options;
var keepAlive = options.keepAlive == null ? true : options.keepAlive;
if (!keepAlive) return;

Expand Down
2 changes: 1 addition & 1 deletion src/client/play.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
var states = require("../states");

module.exports = function(client, options) {
module.exports = function(client) {
client.once('success', onLogin);

function onLogin(packet) {
Expand Down
13 changes: 10 additions & 3 deletions src/client/setProtocol.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@

var states = require("../states");

module.exports = function(client, options) {
module.exports = function(client) {
var options = client.options;
client.on('connect', onConnect);

function onConnect() {
if (options.wait_connect) {
client.on('connect_allowed', next);
} else {
next();
}
}

function next() {
var taggedHost = options.host;
if (options.tagHost) taggedHost += options.tagHost;

Expand All @@ -19,6 +28,4 @@ module.exports = function(client, options) {
username: client.username
});
}


}
3 changes: 2 additions & 1 deletion src/client/tcp_dns.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
var net = require('net');
var dns = require('dns');

module.exports = function(client, options) {
module.exports = function(client) {
var options = client.options;
options.port = options.port || 25565;
options.host = options.host || 'localhost';

Expand Down
21 changes: 13 additions & 8 deletions src/createClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,34 @@ var setProtocol = require('./client/setProtocol');
var play = require('./client/play');
var tcp_dns = require('./client/tcp_dns');
var forgeHandshake = require('./client/forgeHandshake');
var autoVersion = require('./client/autoVersion');

module.exports=createClient;

function createClient(options) {
assert.ok(options, "options is required");
assert.ok(options.username, "username is required");

// TODO: avoid setting default version if autoVersion is enabled
var optVersion = options.version || require("./version").defaultVersion;
var mcData=require("minecraft-data")(optVersion);
if (!mcData) throw new Error(`unsupported protocol version: ${optVersion}`);
var version = mcData.version;
options.majorVersion = version.majorVersion;
options.protocolVersion = version.version;

var client = new Client(false, options.majorVersion);
client.options = options;

tcp_dns(client, options);
if (options.forgeMods) forgeHandshake(client, options);
setProtocol(client, options);
keepalive(client, options);
encrypt(client, options);
play(client, options);
compress(client, options);
caseCorrect(client, options);
tcp_dns(client);
if (options.forgeMods) forgeHandshake(client);
caseCorrect(client);
if (options.version === false) autoVersion(client);
setProtocol(client);
keepalive(client);
encrypt(client);
play(client);
compress(client);

return client;
}
3 changes: 2 additions & 1 deletion src/ping.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ function ping(options, cb) {
options.protocolVersion = version.version;

var client = new Client(false,options.majorVersion);
client.options = options;
client.on('error', function(err) {
cb(err);
});
Expand Down Expand Up @@ -46,6 +47,6 @@ function ping(options, cb) {
client.state = states.STATUS;
});

tcp_dns(client, options);
tcp_dns(client);
options.connect(client);
}

0 comments on commit ba89e24

Please sign in to comment.