mirror of
https://github.com/unmojang/node-minecraft-protocol.git
synced 2025-09-30 14:41:27 -04:00
enable cross version with an option in createClient and createServer :
* put parsePacketData in deserializer and createPacketBuffer in serializer * remove packets from the index and expose readPacket instead * load packets when needed in various files * make tests test every supported version static cross version of #234, fix #65, fix #240
This commit is contained in:
parent
df2caf74cb
commit
917b6adda1
@ -7,7 +7,7 @@ Parse and serialize minecraft packets, plus authentication and encryption.
|
|||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
* Supports Minecraft version 1.8.8
|
* Supports Minecraft version 1.8.8 and 1.9
|
||||||
* Parses all packets and emits events with packet fields as JavaScript
|
* Parses all packets and emits events with packet fields as JavaScript
|
||||||
objects.
|
objects.
|
||||||
* Send a packet by supplying fields as a JavaScript object.
|
* Send a packet by supplying fields as a JavaScript object.
|
||||||
@ -121,8 +121,7 @@ See [doc](doc/README.md)
|
|||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
* Ensure your system has the `java` executable in `PATH`.
|
* Ensure your system has the `java` executable in `PATH`.
|
||||||
* Download the appropriate version of `minecraft_server.jar`.
|
* `MC_SERVER_JAR_DIR=some/path/to/store/minecraft/server/ MC_USERNAME=email@example.com MC_PASSWORD=password npm test`
|
||||||
* `MC_SERVER_JAR=path/to/minecraft_server.jar MC_USERNAME=email@example.com MC_PASSWORD=password npm test`
|
|
||||||
|
|
||||||
## Debugging
|
## Debugging
|
||||||
|
|
||||||
|
10
circle.yml
10
circle.yml
@ -1,12 +1,10 @@
|
|||||||
machine:
|
machine:
|
||||||
environment:
|
environment:
|
||||||
MC_SERVER_JAR: /home/ubuntu/node-minecraft-protocol/minecraft-server/minecraft_server.jar
|
MC_SERVER_JAR_DIR: /home/ubuntu/node-minecraft-protocol/minecraft-server/
|
||||||
node:
|
node:
|
||||||
version: 0.10.28
|
version: 0.10.28
|
||||||
java:
|
java:
|
||||||
version: openjdk7
|
version: openjdk7
|
||||||
test:
|
dependencies:
|
||||||
override:
|
pre:
|
||||||
- mkdir -p /home/ubuntu/node-minecraft-protocol/minecraft-server/
|
- mkdir minecraft-server
|
||||||
- node_modules/.bin/downloadMinecraft `node -e 'console.log(require("./src/version").minecraftVersion)'` $MC_SERVER_JAR
|
|
||||||
- npm test
|
|
||||||
|
@ -84,6 +84,7 @@ Returns a `Client` instance and perform login.
|
|||||||
* clientToken : generated if a password is given
|
* clientToken : generated if a password is given
|
||||||
* accessToken : generated if a password is given
|
* accessToken : generated if a password is given
|
||||||
* keepAlive : send keep alive packets : default to true
|
* keepAlive : send keep alive packets : default to true
|
||||||
|
* version : 1.8 or 1.9
|
||||||
|
|
||||||
## Client
|
## Client
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
"gulp-plumber": "^1.0.1",
|
"gulp-plumber": "^1.0.1",
|
||||||
"gulp-sourcemaps": "^1.3.0",
|
"gulp-sourcemaps": "^1.3.0",
|
||||||
"intelli-espower-loader": "^1.0.0",
|
"intelli-espower-loader": "^1.0.0",
|
||||||
"mocha": "~1.8.2",
|
"mocha": "~2.3.3",
|
||||||
"power-assert": "^1.0.0",
|
"power-assert": "^1.0.0",
|
||||||
"source-map-support": "^0.3.2",
|
"source-map-support": "^0.3.2",
|
||||||
"minecraft-wrap": "~0.5.4"
|
"minecraft-wrap": "~0.5.4"
|
||||||
|
@ -1,19 +1,12 @@
|
|||||||
var version = require('./version');
|
|
||||||
var packets = require('minecraft-data')(version.majorVersion).protocol.states;
|
|
||||||
var readPackets = require("./packets").readPackets;
|
var readPackets = require("./packets").readPackets;
|
||||||
var packetIndexes = readPackets(packets, states);
|
|
||||||
var utils = require("./utils");
|
var utils = require("./utils");
|
||||||
var serializer = require("./transforms/serializer");
|
var serializer = require("./transforms/serializer");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
Client: require('./client'),
|
Client: require('./client'),
|
||||||
protocol: require('./protocol'),
|
protocol: require('./protocol'),
|
||||||
createPacketBuffer: serializer.createPacketBuffer,
|
|
||||||
parsePacketData: serializer.parsePacketData,
|
|
||||||
packetFields: packetIndexes.packetFields,
|
|
||||||
packetNames: packetIndexes.packetNames,
|
|
||||||
packetIds: packetIndexes.packetIds,
|
|
||||||
packetStates: packetIndexes.packetStates,
|
|
||||||
types: serializer.types,
|
types: serializer.types,
|
||||||
get: serializer.get,
|
get: serializer.get,
|
||||||
|
readPackets:readPackets,
|
||||||
|
supportedVersions:require("./version").supportedVersions
|
||||||
};
|
};
|
||||||
|
@ -5,10 +5,6 @@ var compression = require('./transforms/compression');
|
|||||||
var framing = require('./transforms/framing');
|
var framing = require('./transforms/framing');
|
||||||
var crypto = require('crypto');
|
var crypto = require('crypto');
|
||||||
var states = serializer.states;
|
var states = serializer.states;
|
||||||
var version = require('./version');
|
|
||||||
var packets = require('minecraft-data')(version.majorVersion).protocol.states;
|
|
||||||
var readPackets = require("./packets").readPackets;
|
|
||||||
var packetIndexes = readPackets(packets, states);
|
|
||||||
|
|
||||||
|
|
||||||
class Client extends EventEmitter
|
class Client extends EventEmitter
|
||||||
@ -24,11 +20,16 @@ class Client extends EventEmitter
|
|||||||
deserializer;
|
deserializer;
|
||||||
isServer;
|
isServer;
|
||||||
|
|
||||||
constructor(isServer) {
|
constructor(isServer,version) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.serializer = serializer.createSerializer({ isServer });
|
var mcData=require("minecraft-data")(version);
|
||||||
this.deserializer = serializer.createDeserializer({ isServer, packetsToParse: this.packetsToParse });
|
var packets = mcData.protocol.states;
|
||||||
|
var readPackets = require("./packets").readPackets;
|
||||||
|
var packetIndexes = readPackets(packets, states);
|
||||||
|
|
||||||
|
this.serializer = serializer.createSerializer({ isServer, version:version});
|
||||||
|
this.deserializer = serializer.createDeserializer({ isServer, packetsToParse: this.packetsToParse, version:version});
|
||||||
this.isServer = !!isServer;
|
this.isServer = !!isServer;
|
||||||
|
|
||||||
this.on('newListener', function(event, listener) {
|
this.on('newListener', function(event, listener) {
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
var mcHexDigest=require("./mcHexDigest");
|
var mcHexDigest=require("./mcHexDigest");
|
||||||
var ursa=require("./ursa");
|
var ursa=require("./ursa");
|
||||||
var version = require("./version");
|
|
||||||
var net = require('net');
|
var net = require('net');
|
||||||
var dns = require('dns');
|
var dns = require('dns');
|
||||||
var Client = require('./client');
|
var Client = require('./client');
|
||||||
@ -42,8 +41,12 @@ function createClient(options) {
|
|||||||
var haveCredentials = options.password != null || (clientToken != null && accessToken != null);
|
var haveCredentials = options.password != null || (clientToken != null && accessToken != null);
|
||||||
var keepAlive = options.keepAlive == null ? true : options.keepAlive;
|
var keepAlive = options.keepAlive == null ? true : options.keepAlive;
|
||||||
|
|
||||||
|
var optVersion = options.version || require("./version").defaultVersion;
|
||||||
|
var mcData=require("minecraft-data")(optVersion);
|
||||||
|
var version = mcData.version;
|
||||||
|
|
||||||
var client = new Client(false);
|
|
||||||
|
var client = new Client(false,version.majorVersion);
|
||||||
client.on('connect', onConnect);
|
client.on('connect', onConnect);
|
||||||
if(keepAlive) client.on('keep_alive', onKeepAlive);
|
if(keepAlive) client.on('keep_alive', onKeepAlive);
|
||||||
client.once('encryption_begin', onEncryptionKeyRequest);
|
client.once('encryption_begin', onEncryptionKeyRequest);
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
var mcHexDigest=require("./mcHexDigest");
|
var mcHexDigest=require("./mcHexDigest");
|
||||||
var ursa=require("./ursa");
|
var ursa=require("./ursa");
|
||||||
var version = require("./version");
|
|
||||||
var crypto = require('crypto');
|
var crypto = require('crypto');
|
||||||
var Yggdrasil = require('./yggdrasil.js');
|
var Yggdrasil = require('./yggdrasil.js');
|
||||||
var validateSession = Yggdrasil.validateSession;
|
var validateSession = Yggdrasil.validateSession;
|
||||||
@ -28,9 +27,13 @@ function createServer(options) {
|
|||||||
|
|
||||||
var enableKeepAlive = options.keepAlive == null ? true : options.keepAlive;
|
var enableKeepAlive = options.keepAlive == null ? true : options.keepAlive;
|
||||||
|
|
||||||
|
var optVersion = options.version || require("./version").defaultVersion;
|
||||||
|
var mcData=require("minecraft-data")(optVersion);
|
||||||
|
var version = mcData.version;
|
||||||
|
|
||||||
var serverKey = ursa.generatePrivateKey(1024);
|
var serverKey = ursa.generatePrivateKey(1024);
|
||||||
|
|
||||||
var server = new Server(options);
|
var server = new Server(version.majorVersion);
|
||||||
server.motd = options.motd || "A Minecraft server";
|
server.motd = options.motd || "A Minecraft server";
|
||||||
server.maxPlayers = options['max-players'] || 20;
|
server.maxPlayers = options['max-players'] || 20;
|
||||||
server.playerCount = 0;
|
server.playerCount = 0;
|
||||||
|
17
src/index.js
17
src/index.js
@ -3,10 +3,7 @@ var Server = require('./server');
|
|||||||
var Yggdrasil = require('./yggdrasil.js');
|
var Yggdrasil = require('./yggdrasil.js');
|
||||||
var serializer = require("./transforms/serializer");
|
var serializer = require("./transforms/serializer");
|
||||||
var utils = require("./utils");
|
var utils = require("./utils");
|
||||||
var version = require("./version");
|
|
||||||
var packets = require('minecraft-data')(version.majorVersion).protocol.states;
|
|
||||||
var readPackets = require("./packets").readPackets;
|
var readPackets = require("./packets").readPackets;
|
||||||
var packetIndexes = readPackets(packets, serializer.states);
|
|
||||||
var createClient = require("./createClient");
|
var createClient = require("./createClient");
|
||||||
var createServer = require("./createServer");
|
var createServer = require("./createServer");
|
||||||
|
|
||||||
@ -16,16 +13,10 @@ module.exports = {
|
|||||||
Client: Client,
|
Client: Client,
|
||||||
Server: Server,
|
Server: Server,
|
||||||
states: serializer.states,
|
states: serializer.states,
|
||||||
createPacketBuffer: serializer.createPacketBuffer,
|
createSerializer:serializer.createSerializer,
|
||||||
parsePacketData: serializer.parsePacketData,
|
createDeserializer:serializer.createDeserializer,
|
||||||
packetFields: packetIndexes.packetFields,
|
readPackets:readPackets,
|
||||||
packetNames: packetIndexes.packetNames,
|
|
||||||
packetIds: packetIndexes.packetIds,
|
|
||||||
packetStates: packetIndexes.packetStates,
|
|
||||||
types: serializer.types,
|
|
||||||
get: serializer.get,
|
|
||||||
ping: require('./ping'),
|
ping: require('./ping'),
|
||||||
yggdrasil: Yggdrasil,
|
yggdrasil: Yggdrasil,
|
||||||
version: version.version,
|
supportedVersions:require("./version").supportedVersions
|
||||||
minecraftVersion: version.minecraftVersion
|
|
||||||
};
|
};
|
||||||
|
12
src/ping.js
12
src/ping.js
@ -1,15 +1,17 @@
|
|||||||
var net = require('net')
|
var net = require('net');
|
||||||
, Client = require('./client')
|
var Client = require('./client');
|
||||||
, states = require('./transforms/serializer').states;
|
var states = require('./transforms/serializer').states;
|
||||||
var version = require('./version');
|
|
||||||
|
|
||||||
module.exports = ping;
|
module.exports = ping;
|
||||||
|
|
||||||
function ping(options, cb) {
|
function ping(options, cb) {
|
||||||
var host = options.host || 'localhost';
|
var host = options.host || 'localhost';
|
||||||
var port = options.port || 25565;
|
var port = options.port || 25565;
|
||||||
|
var optVersion = options.version || require("./version").defaultVersion;
|
||||||
|
var mcData=require("minecraft-data")(optVersion);
|
||||||
|
var version = mcData.version;
|
||||||
|
|
||||||
var client = new Client();
|
var client = new Client(false,version.majorVersion);
|
||||||
client.on('error', function(err) {
|
client.on('error', function(err) {
|
||||||
cb(err);
|
cb(err);
|
||||||
});
|
});
|
||||||
|
@ -10,16 +10,17 @@ class Server extends EventEmitter
|
|||||||
decipher=null;
|
decipher=null;
|
||||||
clients={};
|
clients={};
|
||||||
|
|
||||||
constructor() {
|
constructor(version) {
|
||||||
super();
|
super();
|
||||||
|
this.version=version;
|
||||||
}
|
}
|
||||||
|
|
||||||
listen(port, host) {
|
listen(port, host) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var nextId = 0;
|
var nextId = 0;
|
||||||
self.socketServer = net.createServer();
|
self.socketServer = net.createServer();
|
||||||
self.socketServer.on('connection', function(socket) {
|
self.socketServer.on('connection', socket => {
|
||||||
var client = new Client(true);
|
var client = new Client(true,this.version);
|
||||||
client._end = client.end;
|
client._end = client.end;
|
||||||
client.end = function end(endReason) {
|
client.end = function end(endReason) {
|
||||||
endReason='{"text":"'+endReason+'"}';
|
endReason='{"text":"'+endReason+'"}';
|
||||||
|
@ -13,9 +13,6 @@ module.exports.createDeserializer = function(obj) {
|
|||||||
return new Deserializer(obj);
|
return new Deserializer(obj);
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.createPacketBuffer=createPacketBuffer;
|
|
||||||
module.exports.parsePacketData=parsePacketData;
|
|
||||||
|
|
||||||
// This is really just for the client.
|
// This is really just for the client.
|
||||||
var states = {
|
var states = {
|
||||||
"HANDSHAKING": "handshaking",
|
"HANDSHAKING": "handshaking",
|
||||||
@ -25,54 +22,61 @@ var states = {
|
|||||||
};
|
};
|
||||||
module.exports.states = states;
|
module.exports.states = states;
|
||||||
|
|
||||||
module.exports.get = get;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var NMProtocols = require("../protocol");
|
var NMProtocols = require("../protocol");
|
||||||
|
|
||||||
var numeric = require("../datatypes/numeric");
|
var numeric = require("../datatypes/numeric");
|
||||||
var utils = require("../datatypes/utils");
|
var utils = require("../datatypes/utils");
|
||||||
var minecraft = require("../datatypes/minecraft");
|
var minecraft = require("../datatypes/minecraft");
|
||||||
var structures = require("../datatypes/structures");
|
var structures = require("../datatypes/structures");
|
||||||
var conditional = require("../datatypes/conditional");
|
var conditional = require("../datatypes/conditional");
|
||||||
|
var readPackets = require("../packets").readPackets;
|
||||||
|
|
||||||
|
|
||||||
|
function createProtocol(types)
|
||||||
|
{
|
||||||
var proto = new NMProtocols();
|
var proto = new NMProtocols();
|
||||||
proto.addTypes(numeric);
|
proto.addTypes(numeric);
|
||||||
proto.addTypes(utils);
|
proto.addTypes(utils);
|
||||||
proto.addTypes(minecraft);
|
proto.addTypes(minecraft);
|
||||||
proto.addTypes(structures);
|
proto.addTypes(structures);
|
||||||
proto.addTypes(conditional);
|
proto.addTypes(conditional);
|
||||||
|
proto.addTypes(types);
|
||||||
|
return proto;
|
||||||
|
}
|
||||||
|
|
||||||
module.exports.types = proto.types;
|
|
||||||
|
|
||||||
var version = require('../version');
|
class Serializer extends Transform {
|
||||||
var packets = require('minecraft-data')(version.majorVersion).protocol;
|
constructor({ state = states.HANDSHAKING, isServer = false , version} = {}) {
|
||||||
proto.addTypes(packets.types);
|
super({ writableObjectMode: true });
|
||||||
|
this.protocolState = state;
|
||||||
|
this.isServer = isServer;
|
||||||
|
this.version = version;
|
||||||
|
|
||||||
var readPackets = require("../packets").readPackets;
|
var mcData=require("minecraft-data")(version);
|
||||||
var packetIndexes = readPackets(packets.states, states);
|
var packets = mcData.protocol.states;
|
||||||
|
var packetIndexes = readPackets(packets, states);
|
||||||
|
|
||||||
var packetFields = packetIndexes.packetFields;
|
this.proto=createProtocol(mcData.protocol.types);
|
||||||
var packetNames = packetIndexes.packetNames;
|
|
||||||
var packetIds = packetIndexes.packetIds;
|
|
||||||
var packetStates = packetIndexes.packetStates;
|
|
||||||
|
|
||||||
|
this.packetFields = packetIndexes.packetFields;
|
||||||
|
this.packetIds = packetIndexes.packetIds;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO : This does NOT contain the length prefix anymore.
|
// TODO : This does NOT contain the length prefix anymore.
|
||||||
function createPacketBuffer(packetName, state, params, isServer) {
|
createPacketBuffer(packetName, params) {
|
||||||
var direction = !isServer ? 'toServer' : 'toClient';
|
var direction = !this.isServer ? 'toServer' : 'toClient';
|
||||||
var packetId = packetIds[state][direction][packetName];
|
var packetId = this.packetIds[this.protocolState][direction][packetName];
|
||||||
assert.notEqual(packetId, undefined, `${state}.${isServer}.${packetName} : ${packetId}`);
|
assert.notEqual(packetId, undefined, `${this.protocolState}.${this.isServer}.${packetName} : ${packetId}`);
|
||||||
var packet = get(packetName, state, !isServer);
|
var packet = this.packetFields[this.protocolState][direction][packetName];
|
||||||
|
packet=packet ? packet : null;
|
||||||
|
|
||||||
assert.notEqual(packet, null);
|
assert.notEqual(packet, null);
|
||||||
|
|
||||||
var length = utils.varint[2](packetId);
|
var length = utils.varint[2](packetId);
|
||||||
tryCatch(() => {
|
tryCatch(() => {
|
||||||
length += structures.container[2].call(proto, params, packet, {});
|
length += structures.container[2].call(this.proto, params, packet, {});
|
||||||
//length += proto.sizeOf(params, ["container", packet], {});
|
//length += proto.sizeOf(params, ["container", packet], {});
|
||||||
}, (e) => {
|
}, (e) => {
|
||||||
e.field = [state, direction, packetName, e.field].join(".");
|
e.field = [this.protocolState, direction, packetName, e.field].join(".");
|
||||||
e.message = `SizeOf error for ${e.field} : ${e.message}`;
|
e.message = `SizeOf error for ${e.field} : ${e.message}`;
|
||||||
throw e;
|
throw e;
|
||||||
});
|
});
|
||||||
@ -80,36 +84,56 @@ function createPacketBuffer(packetName, state, params, isServer) {
|
|||||||
var buffer = new Buffer(length);
|
var buffer = new Buffer(length);
|
||||||
var offset = utils.varint[1](packetId, buffer, 0);
|
var offset = utils.varint[1](packetId, buffer, 0);
|
||||||
tryCatch(() => {
|
tryCatch(() => {
|
||||||
offset = structures.container[1].call(proto, params, buffer, offset, packet, {});
|
offset = structures.container[1].call(this.proto, params, buffer, offset, packet, {});
|
||||||
//offset = proto.write(params, buffer, offset, ["container", packet], {});
|
//offset = proto.write(params, buffer, offset, ["container", packet], {});
|
||||||
}, (e) => {
|
}, (e) => {
|
||||||
e.field = [state, direction, packetName, e.field].join(".");
|
e.field = [this.protocolState, direction, packetName, e.field].join(".");
|
||||||
e.message = `Write error for ${e.field} : ${e.message}`;
|
e.message = `Write error for ${e.field} : ${e.message}`;
|
||||||
throw e;
|
throw e;
|
||||||
});
|
});
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_transform(chunk, enc, cb) {
|
||||||
function get(packetName, state, toServer) {
|
try {
|
||||||
var direction = toServer ? "toServer" : "toClient";
|
var buf = this.createPacketBuffer(chunk.packetName, chunk.params);
|
||||||
var packetInfo = packetFields[state][direction][packetName];
|
this.push(buf);
|
||||||
if(!packetInfo) {
|
return cb();
|
||||||
return null;
|
} catch (e) {
|
||||||
|
return cb(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return packetInfo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function parsePacketData(buffer, state, isServer, packetsToParse = {"packet": true}) {
|
class Deserializer extends Transform {
|
||||||
|
constructor({ state = states.HANDSHAKING, isServer = false, packetsToParse = {"packet": true}, version } = {}) {
|
||||||
|
super({ readableObjectMode: true });
|
||||||
|
this.protocolState = state;
|
||||||
|
this.isServer = isServer;
|
||||||
|
this.packetsToParse = packetsToParse;
|
||||||
|
this.version = version;
|
||||||
|
|
||||||
|
|
||||||
|
var mcData=require("minecraft-data")(version);
|
||||||
|
var packets = mcData.protocol.states;
|
||||||
|
var packetIndexes = readPackets(packets, states);
|
||||||
|
|
||||||
|
this.proto=createProtocol(mcData.protocol.types);
|
||||||
|
|
||||||
|
this.packetFields = packetIndexes.packetFields;
|
||||||
|
this.packetNames = packetIndexes.packetNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
parsePacketData(buffer) {
|
||||||
var { value: packetId, size: cursor } = utils.varint[0](buffer, 0);
|
var { value: packetId, size: cursor } = utils.varint[0](buffer, 0);
|
||||||
|
|
||||||
var direction = isServer ? "toServer" : "toClient";
|
var direction = this.isServer ? "toServer" : "toClient";
|
||||||
var packetName = packetNames[state][direction][packetId];
|
var packetName = this.packetNames[this.protocolState][direction][packetId];
|
||||||
var results = {
|
var results = {
|
||||||
metadata: {
|
metadata: {
|
||||||
name: packetName,
|
name: packetName,
|
||||||
id: packetId,
|
id: packetId,
|
||||||
state
|
state:this.protocolState
|
||||||
},
|
},
|
||||||
data: {},
|
data: {},
|
||||||
buffer
|
buffer
|
||||||
@ -118,22 +142,23 @@ function parsePacketData(buffer, state, isServer, packetsToParse = {"packet": tr
|
|||||||
// Only parse the packet if there is a need for it, AKA if there is a listener
|
// Only parse the packet if there is a need for it, AKA if there is a listener
|
||||||
// attached to it.
|
// attached to it.
|
||||||
var shouldParse =
|
var shouldParse =
|
||||||
(packetsToParse.hasOwnProperty(packetName) && packetsToParse[packetName] > 0) ||
|
(this.packetsToParse.hasOwnProperty(packetName) && this.packetsToParse[packetName] > 0) ||
|
||||||
(packetsToParse.hasOwnProperty("packet") && packetsToParse["packet"] > 0);
|
(this.packetsToParse.hasOwnProperty("packet") && this.packetsToParse["packet"] > 0);
|
||||||
if (!shouldParse)
|
if (!shouldParse)
|
||||||
return results;
|
return results;
|
||||||
|
|
||||||
var packetInfo = get(packetName, state, isServer);
|
var packetInfo = this.packetFields[this.protocolState][direction][packetName];
|
||||||
|
packetInfo=packetInfo ? packetInfo : null;
|
||||||
if(packetInfo === null)
|
if(packetInfo === null)
|
||||||
throw new Error("Unrecognized packetId: " + packetId + " (0x" + packetId.toString(16) + ")")
|
throw new Error("Unrecognized packetId: " + packetId + " (0x" + packetId.toString(16) + ")")
|
||||||
else
|
else
|
||||||
debug("read packetId " + state + "." + packetName + " (0x" + packetId.toString(16) + ")");
|
debug("read packetId " + this.protocolState + "." + packetName + " (0x" + packetId.toString(16) + ")");
|
||||||
|
|
||||||
var res;
|
var res;
|
||||||
tryCatch(() => {
|
tryCatch(() => {
|
||||||
res = proto.read(buffer, cursor, ["container", packetInfo], {});
|
res = this.proto.read(buffer, cursor, ["container", packetInfo], {});
|
||||||
}, (e) => {
|
}, (e) => {
|
||||||
e.field = [state, direction, packetName, e.field].join(".");
|
e.field = [this.protocolState, direction, packetName, e.field].join(".");
|
||||||
e.message = `Read error for ${e.field} : ${e.message}`;
|
e.message = `Read error for ${e.field} : ${e.message}`;
|
||||||
throw e;
|
throw e;
|
||||||
});
|
});
|
||||||
@ -146,36 +171,11 @@ function parsePacketData(buffer, state, isServer, packetsToParse = {"packet": tr
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
class Serializer extends Transform {
|
|
||||||
constructor({ state = states.HANDSHAKING, isServer = false } = {}) {
|
|
||||||
super({ writableObjectMode: true });
|
|
||||||
this.protocolState = state;
|
|
||||||
this.isServer = isServer;
|
|
||||||
}
|
|
||||||
|
|
||||||
_transform(chunk, enc, cb) {
|
|
||||||
try {
|
|
||||||
var buf = createPacketBuffer(chunk.packetName, this.protocolState, chunk.params, this.isServer);
|
|
||||||
this.push(buf);
|
|
||||||
return cb();
|
|
||||||
} catch (e) {
|
|
||||||
return cb(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Deserializer extends Transform {
|
|
||||||
constructor({ state = states.HANDSHAKING, isServer = false, packetsToParse = {"packet": true} } = {}) {
|
|
||||||
super({ readableObjectMode: true });
|
|
||||||
this.protocolState = state;
|
|
||||||
this.isServer = isServer;
|
|
||||||
this.packetsToParse = packetsToParse;
|
|
||||||
}
|
|
||||||
|
|
||||||
_transform(chunk, enc, cb) {
|
_transform(chunk, enc, cb) {
|
||||||
var packet;
|
var packet;
|
||||||
try {
|
try {
|
||||||
packet = parsePacketData(chunk, this.protocolState, this.isServer, this.packetsToParse);
|
packet = this.parsePacketData(chunk);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return cb(e);
|
return cb(e);
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
var majorVersion='1.8';
|
module.exports={
|
||||||
var mcData=require("minecraft-data")(majorVersion);
|
defaultVersion:'1.8',
|
||||||
module.exports=mcData.version;
|
supportedVersions:['1.8','1.9']
|
||||||
|
};
|
||||||
|
@ -11,21 +11,24 @@ var testDataWrite = [
|
|||||||
// TODO: add more packets for better quality data
|
// TODO: add more packets for better quality data
|
||||||
];
|
];
|
||||||
|
|
||||||
|
mc.supportedVersions.forEach(function(supportedVersion){
|
||||||
var inputData = [];
|
var inputData = [];
|
||||||
|
var serializer=new mc.createSerializer({state:states.PLAY,isServer:false,version:supportedVersion});
|
||||||
var start, i, j;
|
var start, i, j;
|
||||||
console.log('Beginning write test');
|
console.log('Beginning write test for '+supportedVersion);
|
||||||
start = Date.now();
|
start = Date.now();
|
||||||
for(i = 0; i < ITERATIONS; i++) {
|
for(i = 0; i < ITERATIONS; i++) {
|
||||||
for(j = 0; j < testDataWrite.length; j++) {
|
for(j = 0; j < testDataWrite.length; j++) {
|
||||||
inputData.push(mc.createPacketBuffer(testDataWrite[j].name, states.PLAY, testDataWrite[j].params, false));
|
inputData.push(serializer.createPacketBuffer(testDataWrite[j].name, testDataWrite[j].params));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log('Finished write test in ' + (Date.now() - start) / 1000 + ' seconds');
|
console.log('Finished write test in ' + (Date.now() - start) / 1000 + ' seconds');
|
||||||
|
|
||||||
console.log('Beginning read test');
|
var deserializer=new mc.createDeserializer({state:states.PLAY,isServer:true,version:supportedVersion});
|
||||||
|
console.log('Beginning read test for '+supportedVersion);
|
||||||
start = Date.now();
|
start = Date.now();
|
||||||
for (j = 0; j < inputData.length; j++) {
|
for (j = 0; j < inputData.length; j++) {
|
||||||
mc.parsePacketData(inputData[j], states.PLAY, true);
|
deserializer.parsePacketData(inputData[j]);
|
||||||
}
|
}
|
||||||
console.log('Finished read test in ' + (Date.now() - start) / 1000 + ' seconds');
|
console.log('Finished read test in ' + (Date.now() - start) / 1000 + ' seconds');
|
||||||
|
});
|
||||||
|
145
test/test.js
145
test/test.js
@ -1,20 +1,17 @@
|
|||||||
var mc = require('../')
|
var mc = require('../');
|
||||||
, states = mc.states
|
var states = mc.states;
|
||||||
, Client = mc.Client
|
var Client = mc.Client;
|
||||||
, Server = mc.Server
|
var Server = mc.Server;
|
||||||
, path = require('path')
|
var path = require('path');
|
||||||
, fs = require('fs')
|
var fs = require('fs');
|
||||||
, net = require('net')
|
var net = require('net');
|
||||||
, assert = require('power-assert')
|
var assert = require('power-assert');
|
||||||
, MC_SERVER_JAR = process.env.MC_SERVER_JAR
|
var SURVIVE_TIME = 10000;
|
||||||
, SURVIVE_TIME = 10000
|
var getFieldInfo = require('../dist/utils').getFieldInfo;
|
||||||
, MC_SERVER_PATH = path.join(__dirname, 'server')
|
var getField = require('../dist/utils').getField;
|
||||||
, getFieldInfo = require('../dist/utils').getFieldInfo
|
var MC_SERVER_PATH = path.join(__dirname, 'server');
|
||||||
, getField = require('../dist/utils').getField
|
|
||||||
;
|
|
||||||
|
|
||||||
var Wrap = require('minecraft-wrap').Wrap;
|
var Wrap = require('minecraft-wrap').Wrap;
|
||||||
var wrap=new Wrap(MC_SERVER_JAR,MC_SERVER_PATH);
|
|
||||||
|
|
||||||
function evalCount(count, fields) {
|
function evalCount(count, fields) {
|
||||||
if(fields[count["field"]] in count["map"])
|
if(fields[count["field"]] in count["map"])
|
||||||
@ -48,7 +45,7 @@ var values = {
|
|||||||
},
|
},
|
||||||
'container': function(typeArgs, context) {
|
'container': function(typeArgs, context) {
|
||||||
var results = {
|
var results = {
|
||||||
"..": context;
|
"..": context
|
||||||
};
|
};
|
||||||
for(var index in typeArgs) {
|
for(var index in typeArgs) {
|
||||||
results[typeArgs[index].name] = getValue(typeArgs[index].type, results);
|
results[typeArgs[index].name] = getValue(typeArgs[index].type, results);
|
||||||
@ -111,16 +108,30 @@ function getValue(_type, packet) {
|
|||||||
throw new Error("No value for type " + fieldInfo.type);
|
throw new Error("No value for type " + fieldInfo.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
describe("packets", function() {
|
var download = require('minecraft-wrap').download;
|
||||||
|
|
||||||
|
mc.supportedVersions.forEach(function(supportedVersion){
|
||||||
|
var mcData=require("minecraft-data")(supportedVersion);
|
||||||
|
var version=mcData.version;
|
||||||
|
var MC_SERVER_JAR_DIR = process.env.MC_SERVER_JAR_DIR;
|
||||||
|
var MC_SERVER_JAR = MC_SERVER_JAR_DIR+"/minecraft_server."+version.minecraftVersion+".jar";
|
||||||
|
var wrap=new Wrap(MC_SERVER_JAR,MC_SERVER_PATH);
|
||||||
|
|
||||||
|
var packets = mcData.protocol.states;
|
||||||
|
var packetIndexes = mc.readPackets(packets, states);
|
||||||
|
var packetFields = packetIndexes.packetFields;
|
||||||
|
|
||||||
|
|
||||||
|
describe("packets "+version.minecraftVersion, function() {
|
||||||
var client, server, serverClient;
|
var client, server, serverClient;
|
||||||
before(function(done) {
|
before(function(done) {
|
||||||
server = new Server();
|
server = new Server(version.majorVersion);
|
||||||
server.once('listening', function() {
|
server.once('listening', function() {
|
||||||
server.once('connection', function(c) {
|
server.once('connection', function(c) {
|
||||||
serverClient = c;
|
serverClient = c;
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
client = new Client();
|
client = new Client(false,version.majorVersion);
|
||||||
client.setSocket(net.connect(25565, 'localhost'));
|
client.setSocket(net.connect(25565, 'localhost'));
|
||||||
});
|
});
|
||||||
server.listen(25565, 'localhost');
|
server.listen(25565, 'localhost');
|
||||||
@ -133,17 +144,19 @@ describe("packets", function() {
|
|||||||
client.end();
|
client.end();
|
||||||
});
|
});
|
||||||
var packetName, packetInfo, field;
|
var packetName, packetInfo, field;
|
||||||
for(state in mc.packetFields) {
|
for(state in packetFields) {
|
||||||
if(!mc.packetFields.hasOwnProperty(state)) continue;
|
if(!packetFields.hasOwnProperty(state)) continue;
|
||||||
for(packetName in mc.packetFields[state].toServer) {
|
for(packetName in packetFields[state].toServer) {
|
||||||
if(!mc.packetFields[state].toServer.hasOwnProperty(packetName)) continue;
|
if(!packetFields[state].toServer.hasOwnProperty(packetName)) continue;
|
||||||
packetInfo = mc.get(packetName, state, true);
|
packetInfo = packetFields[state]["toServer"][packetName];
|
||||||
|
packetInfo=packetInfo ? packetInfo : null;
|
||||||
it(state + ",ServerBound," + packetName,
|
it(state + ",ServerBound," + packetName,
|
||||||
callTestPacket(packetName, packetInfo, state, true));
|
callTestPacket(packetName, packetInfo, state, true));
|
||||||
}
|
}
|
||||||
for(packetName in mc.packetFields[state].toClient) {
|
for(packetName in packetFields[state].toClient) {
|
||||||
if(!mc.packetFields[state].toClient.hasOwnProperty(packetName)) continue;
|
if(!packetFields[state].toClient.hasOwnProperty(packetName)) continue;
|
||||||
packetInfo = mc.get(packetName, state, false);
|
packetInfo = packetFields[state]["toClient"][packetName];
|
||||||
|
packetInfo=packetInfo ? packetInfo : null;
|
||||||
it(state + ",ClientBound," + packetName,
|
it(state + ",ClientBound," + packetName,
|
||||||
callTestPacket(packetName, packetInfo, state, false));
|
callTestPacket(packetName, packetInfo, state, false));
|
||||||
}
|
}
|
||||||
@ -197,9 +210,19 @@ describe("packets", function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("client", function() {
|
describe("client "+version.minecraftVersion, function() {
|
||||||
this.timeout(10 * 60 * 1000);
|
this.timeout(10 * 60 * 1000);
|
||||||
|
|
||||||
|
before(function(done){
|
||||||
|
console.log(MC_SERVER_JAR);
|
||||||
|
fs.exists(MC_SERVER_JAR,function(exists){
|
||||||
|
if(exists)
|
||||||
|
done();
|
||||||
|
else
|
||||||
|
download(version.minecraftVersion,MC_SERVER_JAR,done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
afterEach(function(done) {
|
afterEach(function(done) {
|
||||||
wrap.stopServer(function(err){
|
wrap.stopServer(function(err){
|
||||||
if(err)
|
if(err)
|
||||||
@ -224,7 +247,9 @@ describe("client", function() {
|
|||||||
}, function(err) {
|
}, function(err) {
|
||||||
if(err)
|
if(err)
|
||||||
return done(err);
|
return done(err);
|
||||||
mc.ping({}, function(err, results) {
|
mc.ping({
|
||||||
|
version: version.majorVersion
|
||||||
|
}, function(err, results) {
|
||||||
if(err) return done(err);
|
if(err) return done(err);
|
||||||
assert.ok(results.latency >= 0);
|
assert.ok(results.latency >= 0);
|
||||||
assert.ok(results.latency <= 1000);
|
assert.ok(results.latency <= 1000);
|
||||||
@ -248,6 +273,7 @@ describe("client", function() {
|
|||||||
var client = mc.createClient({
|
var client = mc.createClient({
|
||||||
username: process.env.MC_USERNAME,
|
username: process.env.MC_USERNAME,
|
||||||
password: process.env.MC_PASSWORD,
|
password: process.env.MC_PASSWORD,
|
||||||
|
version: version.majorVersion
|
||||||
});
|
});
|
||||||
wrap.on('line', function(line) {
|
wrap.on('line', function(line) {
|
||||||
var match = line.match(/\[Server thread\/INFO\]: <(.+?)> (.+)/);
|
var match = line.match(/\[Server thread\/INFO\]: <(.+?)> (.+)/);
|
||||||
@ -278,6 +304,7 @@ describe("client", function() {
|
|||||||
return done(err);
|
return done(err);
|
||||||
var client = mc.createClient({
|
var client = mc.createClient({
|
||||||
username: 'Player',
|
username: 'Player',
|
||||||
|
version: version.majorVersion
|
||||||
});
|
});
|
||||||
wrap.on('line', function(line) {
|
wrap.on('line', function(line) {
|
||||||
var match = line.match(/\[Server thread\/INFO\]: <(.+?)> (.+)/);
|
var match = line.match(/\[Server thread\/INFO\]: <(.+?)> (.+)/);
|
||||||
@ -329,6 +356,7 @@ describe("client", function() {
|
|||||||
return done(err);
|
return done(err);
|
||||||
var client = mc.createClient({
|
var client = mc.createClient({
|
||||||
username: 'Player',
|
username: 'Player',
|
||||||
|
version: version.majorVersion
|
||||||
});
|
});
|
||||||
var gotKicked = false;
|
var gotKicked = false;
|
||||||
client.on('disconnect', function(packet) {
|
client.on('disconnect', function(packet) {
|
||||||
@ -347,6 +375,7 @@ describe("client", function() {
|
|||||||
return done(err);
|
return done(err);
|
||||||
var client = mc.createClient({
|
var client = mc.createClient({
|
||||||
username: 'Player',
|
username: 'Player',
|
||||||
|
version: version.majorVersion
|
||||||
});
|
});
|
||||||
client.on("login", function(packet) {
|
client.on("login", function(packet) {
|
||||||
client.write("chat", {
|
client.write("chat", {
|
||||||
@ -371,9 +400,12 @@ describe("client", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe("mc-server", function() {
|
describe("mc-server "+version.minecraftVersion, function() {
|
||||||
it("starts listening and shuts down cleanly", function(done) {
|
it("starts listening and shuts down cleanly", function(done) {
|
||||||
var server = mc.createServer({'online-mode': false});
|
var server = mc.createServer({
|
||||||
|
'online-mode': false,
|
||||||
|
version: version.majorVersion
|
||||||
|
});
|
||||||
var listening = false;
|
var listening = false;
|
||||||
server.on('listening', function() {
|
server.on('listening', function() {
|
||||||
listening = true;
|
listening = true;
|
||||||
@ -389,6 +421,7 @@ describe("mc-server", function() {
|
|||||||
'online-mode': false,
|
'online-mode': false,
|
||||||
kickTimeout: 100,
|
kickTimeout: 100,
|
||||||
checkTimeoutInterval: 10,
|
checkTimeoutInterval: 10,
|
||||||
|
version: version.majorVersion
|
||||||
});
|
});
|
||||||
var count = 2;
|
var count = 2;
|
||||||
server.on('connection', function(client) {
|
server.on('connection', function(client) {
|
||||||
@ -401,7 +434,7 @@ describe("mc-server", function() {
|
|||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
server.on('listening', function() {
|
server.on('listening', function() {
|
||||||
var client = new mc.Client();
|
var client = new mc.Client(false,version.majorVersion);
|
||||||
client.on('end', function() {
|
client.on('end', function() {
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
@ -418,6 +451,7 @@ describe("mc-server", function() {
|
|||||||
'online-mode': false,
|
'online-mode': false,
|
||||||
kickTimeout: 100,
|
kickTimeout: 100,
|
||||||
checkTimeoutInterval: 10,
|
checkTimeoutInterval: 10,
|
||||||
|
version: version.majorVersion
|
||||||
});
|
});
|
||||||
var count = 2;
|
var count = 2;
|
||||||
server.on('connection', function(client) {
|
server.on('connection', function(client) {
|
||||||
@ -435,6 +469,7 @@ describe("mc-server", function() {
|
|||||||
host: '127.0.0.1',
|
host: '127.0.0.1',
|
||||||
port: 25565,
|
port: 25565,
|
||||||
keepAlive: false,
|
keepAlive: false,
|
||||||
|
version: version.majorVersion
|
||||||
});
|
});
|
||||||
client.on('end', function() {
|
client.on('end', function() {
|
||||||
resolve();
|
resolve();
|
||||||
@ -450,17 +485,21 @@ describe("mc-server", function() {
|
|||||||
'online-mode': false,
|
'online-mode': false,
|
||||||
motd: 'test1234',
|
motd: 'test1234',
|
||||||
'max-players': 120,
|
'max-players': 120,
|
||||||
|
version: version.majorVersion
|
||||||
});
|
});
|
||||||
server.on('listening', function() {
|
server.on('listening', function() {
|
||||||
mc.ping({host: '127.0.0.1'}, function(err, results) {
|
mc.ping({
|
||||||
|
host: '127.0.0.1',
|
||||||
|
version: version.majorVersion
|
||||||
|
}, function(err, results) {
|
||||||
if(err) return done(err);
|
if(err) return done(err);
|
||||||
assert.ok(results.latency >= 0);
|
assert.ok(results.latency >= 0);
|
||||||
assert.ok(results.latency <= 1000);
|
assert.ok(results.latency <= 1000);
|
||||||
delete results.latency;
|
delete results.latency;
|
||||||
assert.deepEqual(results, {
|
assert.deepEqual(results, {
|
||||||
version: {
|
version: {
|
||||||
name: mc.minecraftVersion,
|
name: version.minecraftVersion,
|
||||||
protocol: mc.version
|
protocol: version.version
|
||||||
},
|
},
|
||||||
players: {
|
players: {
|
||||||
max: 120,
|
max: 120,
|
||||||
@ -475,7 +514,10 @@ describe("mc-server", function() {
|
|||||||
server.on('close', done);
|
server.on('close', done);
|
||||||
});
|
});
|
||||||
it("clients can log in and chat", function(done) {
|
it("clients can log in and chat", function(done) {
|
||||||
var server = mc.createServer({'online-mode': false,});
|
var server = mc.createServer({
|
||||||
|
'online-mode': false,
|
||||||
|
version: version.majorVersion
|
||||||
|
});
|
||||||
var username = ['player1', 'player2'];
|
var username = ['player1', 'player2'];
|
||||||
var index = 0;
|
var index = 0;
|
||||||
server.on('login', function(client) {
|
server.on('login', function(client) {
|
||||||
@ -502,7 +544,11 @@ describe("mc-server", function() {
|
|||||||
});
|
});
|
||||||
server.on('close', done);
|
server.on('close', done);
|
||||||
server.on('listening', function() {
|
server.on('listening', function() {
|
||||||
var player1 = mc.createClient({username: 'player1', host: '127.0.0.1'});
|
var player1 = mc.createClient({
|
||||||
|
username: 'player1',
|
||||||
|
host: '127.0.0.1',
|
||||||
|
version: version.majorVersion
|
||||||
|
});
|
||||||
player1.on('login', function(packet) {
|
player1.on('login', function(packet) {
|
||||||
assert.strictEqual(packet.gameMode, 1);
|
assert.strictEqual(packet.gameMode, 1);
|
||||||
assert.strictEqual(packet.levelType, 'default');
|
assert.strictEqual(packet.levelType, 'default');
|
||||||
@ -530,7 +576,11 @@ describe("mc-server", function() {
|
|||||||
});
|
});
|
||||||
player2.write('chat', {message: "hi"});
|
player2.write('chat', {message: "hi"});
|
||||||
});
|
});
|
||||||
var player2 = mc.createClient({username: 'player2', host: '127.0.0.1'});
|
var player2 = mc.createClient({
|
||||||
|
username: 'player2',
|
||||||
|
host: '127.0.0.1',
|
||||||
|
version: version.majorVersion
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -546,7 +596,9 @@ describe("mc-server", function() {
|
|||||||
});
|
});
|
||||||
it("kicks clients when invalid credentials", function(done) {
|
it("kicks clients when invalid credentials", function(done) {
|
||||||
this.timeout(10000);
|
this.timeout(10000);
|
||||||
var server = mc.createServer();
|
var server = mc.createServer({
|
||||||
|
version: version.majorVersion
|
||||||
|
});
|
||||||
var count = 4;
|
var count = 4;
|
||||||
server.on('connection', function(client) {
|
server.on('connection', function(client) {
|
||||||
client.on('end', function(reason) {
|
client.on('end', function(reason) {
|
||||||
@ -561,7 +613,8 @@ describe("mc-server", function() {
|
|||||||
resolve();
|
resolve();
|
||||||
var client = mc.createClient({
|
var client = mc.createClient({
|
||||||
username: 'lalalal',
|
username: 'lalalal',
|
||||||
host: "127.0.0.1"
|
host: "127.0.0.1",
|
||||||
|
version: version.majorVersion
|
||||||
});
|
});
|
||||||
client.on('end', function() {
|
client.on('end', function() {
|
||||||
resolve();
|
resolve();
|
||||||
@ -573,7 +626,10 @@ describe("mc-server", function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
it("gives correct reason for kicking clients when shutting down", function(done) {
|
it("gives correct reason for kicking clients when shutting down", function(done) {
|
||||||
var server = mc.createServer({'online-mode': false,});
|
var server = mc.createServer({
|
||||||
|
'online-mode': false,
|
||||||
|
version: version.majorVersion
|
||||||
|
});
|
||||||
var count = 2;
|
var count = 2;
|
||||||
server.on('login', function(client) {
|
server.on('login', function(client) {
|
||||||
client.on('end', function(reason) {
|
client.on('end', function(reason) {
|
||||||
@ -594,7 +650,11 @@ describe("mc-server", function() {
|
|||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
server.on('listening', function() {
|
server.on('listening', function() {
|
||||||
var client = mc.createClient({username: 'lalalal', host: '127.0.0.1'});
|
var client = mc.createClient({
|
||||||
|
username: 'lalalal',
|
||||||
|
host: '127.0.0.1',
|
||||||
|
version: version.majorVersion
|
||||||
|
});
|
||||||
client.on('login', function() {
|
client.on('login', function() {
|
||||||
server.close();
|
server.close();
|
||||||
});
|
});
|
||||||
@ -605,3 +665,4 @@ describe("mc-server", function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
})
|
||||||
|
Loading…
x
Reference in New Issue
Block a user