minecraft-protocol
Advanced tools
Comparing version 1.3.0 to 1.3.1
# History | ||
## 1.3.1 | ||
* improve autoversion support | ||
* fix tests | ||
## 1.3.0 | ||
@@ -4,0 +9,0 @@ |
{ | ||
"name": "minecraft-protocol", | ||
"version": "1.3.0", | ||
"version": "1.3.1", | ||
"description": "Parse and serialize minecraft packets, plus authentication and encryption.", | ||
@@ -36,3 +36,3 @@ "main": "src/index.js", | ||
"power-assert": "^1.0.0", | ||
"require-self": "^0.1.0" | ||
"require-self": "^0.2.1" | ||
}, | ||
@@ -39,0 +39,0 @@ "dependencies": { |
@@ -25,15 +25,16 @@ 'use strict'; | ||
const protocolVersion = response.version.protocol;// 47, 5 | ||
debug(`Server version: ${brandedMinecraftVersion}, protocol: ${protocolVersion}`); | ||
let minecraftVersion; | ||
if (brandedMinecraftVersion.indexOf(' ') !== -1) { | ||
// Spigot and Glowstone++ prepend their name; strip it off | ||
minecraftVersion = brandedMinecraftVersion.split(' ')[1]; | ||
} else { | ||
minecraftVersion = brandedMinecraftVersion; | ||
let versions = [brandedMinecraftVersion] | ||
.concat(brandedMinecraftVersion.match(/((\d+\.)+\d+)/g)||[]) | ||
.map(function (version) { | ||
return minecraft_data.versionsByMinecraftVersion["pc"][version] | ||
}) | ||
.filter(function (info) { return info }) | ||
.sort(function (a, b) { return b.version - a.version }) | ||
.concat(minecraft_data.postNettyVersionsByProtocolVersion["pc"][protocolVersion]||[]) | ||
if (versions.length === 0) { | ||
throw new Error(`unsupported/unknown protocol version: ${protocolVersion}, update minecraft-data`); | ||
} | ||
const minecraftVersion = versions[0].minecraftVersion; | ||
const versionInfo = minecraft_data.versionsByMinecraftVersion["pc"][minecraftVersion]; | ||
if (!versionInfo) throw new Error(`unsupported/unknown protocol version: ${protocolVersion}, update minecraft-data`); | ||
debug(`Server version: ${minecraftVersion}, protocol: ${protocolVersion}`); | ||
@@ -40,0 +41,0 @@ options.version = minecraftVersion; |
@@ -7,8 +7,16 @@ module.exports = function(client,options) { | ||
const text=parsed.text ? parsed.text : parsed; | ||
const versionRequired=/(?:Outdated client! Please use|Outdated server! I'm still on) (.+)/.exec(text); | ||
let versionRequired; | ||
if(text.translate && text.translate.startsWith("multiplayer.disconnect.outdated_")) | ||
versionRequired=text.with[0]; | ||
else { | ||
versionRequired = /(?:Outdated client! Please use|Outdated server! I'm still on) (.+)/.exec(text); | ||
versionRequired= versionRequired ? versionRequired[1] : null; | ||
} | ||
if(!versionRequired) | ||
return; | ||
client.emit("error",new Error("This server is version "+versionRequired[1]+ | ||
client.emit("error",new Error("This server is version "+versionRequired+ | ||
", you are using version "+client.version+", please specify the correct version in the options.")) | ||
}) | ||
}; |
@@ -25,2 +25,5 @@ var mc = require('../'); | ||
var wrap = new Wrap(MC_SERVER_JAR, MC_SERVER_PATH+"_"+supportedVersion); | ||
wrap.on('line', function(line) { | ||
console.log(line); | ||
}); | ||
@@ -32,5 +35,5 @@ describe("client " + version.minecraftVersion, function() { | ||
afterEach(function(done) { | ||
wrap.stopServer(function(err) { | ||
if(err) | ||
after(function (done) { | ||
wrap.deleteServerData(function (err) { | ||
if (err) | ||
console.log(err); | ||
@@ -40,25 +43,32 @@ done(err); | ||
}); | ||
after(function(done) { | ||
wrap.deleteServerData(function(err) { | ||
if(err) | ||
console.log(err); | ||
done(err); | ||
describe("offline", function () { | ||
before(function (done) { | ||
wrap.startServer({ | ||
'online-mode': 'false', | ||
'server-port': PORT, | ||
'motd': 'test1234', | ||
'max-players': 120 | ||
}, function (err) { | ||
if (err) | ||
console.log(err); | ||
done(err); | ||
}); | ||
}); | ||
}); | ||
it("pings the server", function(done) { | ||
wrap.on('line', function(line) { | ||
console.log(line); | ||
after(function (done) { | ||
wrap.stopServer(function (err) { | ||
if (err) | ||
console.log(err); | ||
done(err); | ||
}); | ||
}); | ||
wrap.startServer({ | ||
motd: 'test1234', | ||
'max-players': 120, | ||
'server-port':PORT | ||
}, function(err) { | ||
if(err) | ||
return done(err); | ||
it("pings the server", function (done) { | ||
mc.ping({ | ||
version: version.minecraftVersion, | ||
port:PORT | ||
}, function(err, results) { | ||
if(err) return done(err); | ||
port: PORT | ||
}, function (err, results) { | ||
if (err) return done(err); | ||
assert.ok(results.latency >= 0); | ||
@@ -78,60 +88,13 @@ assert.ok(results.latency <= 1000); | ||
}); | ||
}); | ||
it.skip("connects successfully - online mode", function(done) { | ||
wrap.startServer({ | ||
'online-mode': 'true', | ||
'server-port':PORT | ||
}, function(err) { | ||
if(err) | ||
return done(err); | ||
it("connects successfully - offline mode", function (done) { | ||
var client = mc.createClient({ | ||
username: process.env.MC_USERNAME, | ||
password: process.env.MC_PASSWORD, | ||
version: version.minecraftVersion, | ||
port:PORT | ||
}); | ||
var lineListener = function(line) { | ||
var match = line.match(/\[Server thread\/INFO\]: <(.+?)> (.+)/); | ||
if(!match) return; | ||
assert.strictEqual(match[1], client.username); | ||
assert.strictEqual(match[2], "hello everyone; I have logged in."); | ||
wrap.writeServer("say hello\n"); | ||
}; | ||
wrap.on('line', lineListener); | ||
client.on('login', function(packet) { | ||
assert.strictEqual(packet.levelType, 'default'); | ||
assert.strictEqual(packet.difficulty, 1); | ||
assert.strictEqual(packet.dimension, 0); | ||
assert.strictEqual(packet.gameMode, 0); | ||
client.write('chat', { | ||
message: "hello everyone; I have logged in." | ||
}); | ||
}); | ||
var chatCount = 0; | ||
client.on('chat', function(packet) { | ||
chatCount += 1; | ||
assert.ok(chatCount <= 2); | ||
if(chatCount == 2) { | ||
client.removeAllListeners('chat'); | ||
wrap.removeListener('line', lineListener); | ||
done(); | ||
} | ||
}); | ||
}); | ||
}); | ||
it("connects successfully - offline mode", function(done) { | ||
wrap.startServer({ | ||
'online-mode': 'false', | ||
'server-port':PORT | ||
}, function(err) { | ||
if(err) | ||
return done(err); | ||
var client = mc.createClient({ | ||
username: 'Player', | ||
version: version.minecraftVersion, | ||
port:PORT | ||
port: PORT | ||
}); | ||
var lineListener = function(line) { | ||
var lineListener = function (line) { | ||
var match = line.match(/\[Server thread\/INFO\]: <(.+?)> (.+)/); | ||
if(!match) return; | ||
if (!match) return; | ||
assert.strictEqual(match[1], 'Player'); | ||
@@ -143,3 +106,3 @@ assert.strictEqual(match[2], "hello everyone; I have logged in."); | ||
var chatCount = 0; | ||
client.on('login', function(packet) { | ||
client.on('login', function (packet) { | ||
assert.strictEqual(packet.levelType, 'default'); | ||
@@ -153,7 +116,7 @@ assert.strictEqual(packet.difficulty, 1); | ||
}); | ||
client.on('chat', function(packet) { | ||
client.on('chat', function (packet) { | ||
chatCount += 1; | ||
assert.ok(chatCount <= 2); | ||
var message = JSON.parse(packet.message); | ||
if(chatCount === 1) { | ||
if (chatCount === 1) { | ||
assert.strictEqual(message.translate, "chat.type.text"); | ||
@@ -166,3 +129,3 @@ assert.deepEqual(message["with"][0].clickEvent, { | ||
assert.strictEqual(message["with"][1], "hello everyone; I have logged in."); | ||
} else if(chatCount === 2) { | ||
} else if (chatCount === 2) { | ||
assert.strictEqual(message.translate, "chat.type.announcement"); | ||
@@ -173,2 +136,3 @@ assert.strictEqual(message["with"][0].text ? message["with"][0].text : message["with"][0], "Server"); | ||
wrap.removeListener('line', lineListener); | ||
client.end(); | ||
done(); | ||
@@ -178,39 +142,11 @@ } | ||
}); | ||
}); | ||
it("gets kicked when no credentials supplied in online mode", function(done) { | ||
wrap.startServer({ | ||
'online-mode': 'true', | ||
'server-port':PORT | ||
}, function(err) { | ||
if(err) | ||
return done(err); | ||
it("does not crash for " + SURVIVE_TIME + "ms", function (done) { | ||
var client = mc.createClient({ | ||
username: 'Player', | ||
version: version.minecraftVersion, | ||
port:PORT | ||
port: PORT | ||
}); | ||
var gotKicked = false; | ||
client.on('disconnect', function(packet) { | ||
assert.ok(packet.reason.indexOf('"Failed to verify username!"') != -1); | ||
gotKicked = true; | ||
}); | ||
client.on('end', function() { | ||
assert.ok(gotKicked); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
it("does not crash for " + SURVIVE_TIME + "ms", function(done) { | ||
wrap.startServer({ | ||
'online-mode': 'false', | ||
'server-port':PORT | ||
}, function(err) { | ||
if(err) | ||
return done(err); | ||
var client = mc.createClient({ | ||
username: 'Player', | ||
version: version.minecraftVersion, | ||
port:PORT | ||
}); | ||
client.on("login", function(packet) { | ||
client.on("login", function (packet) { | ||
client.write("chat", { | ||
@@ -220,3 +156,3 @@ message: "hello everyone; I have logged in." | ||
}); | ||
client.on("chat", function(packet) { | ||
client.on("chat", function (packet) { | ||
var message = JSON.parse(packet.message); | ||
@@ -232,3 +168,4 @@ assert.strictEqual(message.translate, "chat.type.text"); | ||
assert.strictEqual(message["with"][1], "hello everyone; I have logged in."); | ||
setTimeout(function() { | ||
setTimeout(function () { | ||
client.end(); | ||
done(); | ||
@@ -238,19 +175,12 @@ }, SURVIVE_TIME); | ||
}); | ||
}); | ||
it("produce a decent error when connecting with the wrong version",function(done) { | ||
wrap.startServer({ | ||
'online-mode': 'false', | ||
'server-port':PORT | ||
}, function(err) { | ||
if(err) | ||
return done(err); | ||
it("produce a decent error when connecting with the wrong version", function (done) { | ||
var client = mc.createClient({ | ||
username: 'Player', | ||
version: version.minecraftVersion=="1.8.8" ? "1.11.2" : "1.8.8", | ||
port:PORT | ||
version: version.minecraftVersion == "1.8.8" ? "1.11.2" : "1.8.8", | ||
port: PORT | ||
}); | ||
client.once("error",function(err) { | ||
if(err.message.startsWith("This server is version")) { | ||
console.log("Correctly got an error for wrong version : "+err.message); | ||
client.once("error", function (err) { | ||
if (err.message.startsWith("This server is version")) { | ||
console.log("Correctly got an error for wrong version : " + err.message); | ||
done(); | ||
@@ -262,5 +192,82 @@ } | ||
}); | ||
}) | ||
}) | ||
}); | ||
}); | ||
describe("online", function () { | ||
before(function (done) { | ||
wrap.startServer({ | ||
'online-mode': 'true', | ||
'server-port': PORT | ||
}, function (err) { | ||
if (err) | ||
console.log(err); | ||
done(err); | ||
}); | ||
}); | ||
after(function (done) { | ||
wrap.stopServer(function (err) { | ||
if (err) | ||
console.log(err); | ||
done(err); | ||
}); | ||
}); | ||
it.skip("connects successfully - online mode", function (done) { | ||
var client = mc.createClient({ | ||
username: process.env.MC_USERNAME, | ||
password: process.env.MC_PASSWORD, | ||
version: version.minecraftVersion, | ||
port: PORT | ||
}); | ||
var lineListener = function (line) { | ||
var match = line.match(/\[Server thread\/INFO\]: <(.+?)> (.+)/); | ||
if (!match) return; | ||
assert.strictEqual(match[1], client.username); | ||
assert.strictEqual(match[2], "hello everyone; I have logged in."); | ||
wrap.writeServer("say hello\n"); | ||
}; | ||
wrap.on('line', lineListener); | ||
client.on('login', function (packet) { | ||
assert.strictEqual(packet.levelType, 'default'); | ||
assert.strictEqual(packet.difficulty, 1); | ||
assert.strictEqual(packet.dimension, 0); | ||
assert.strictEqual(packet.gameMode, 0); | ||
client.write('chat', { | ||
message: "hello everyone; I have logged in." | ||
}); | ||
}); | ||
var chatCount = 0; | ||
client.on('chat', function (packet) { | ||
chatCount += 1; | ||
assert.ok(chatCount <= 2); | ||
if (chatCount == 2) { | ||
client.removeAllListeners('chat'); | ||
wrap.removeListener('line', lineListener); | ||
client.end(); | ||
done(); | ||
} | ||
}); | ||
}); | ||
it("gets kicked when no credentials supplied in online mode", function (done) { | ||
var client = mc.createClient({ | ||
username: 'Player', | ||
version: version.minecraftVersion, | ||
port: PORT | ||
}); | ||
var gotKicked = false; | ||
client.on('disconnect', function (packet) { | ||
assert.ok(packet.reason.indexOf('"Failed to verify username!"') != -1 || packet.reason.indexOf('multiplayer.disconnect.unverified_username') != -1); | ||
gotKicked = true; | ||
}); | ||
client.on('end', function () { | ||
assert.ok(gotKicked); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); |
@@ -20,3 +20,3 @@ var mc = require('../'); | ||
'u16': 123, | ||
'varint': 25992, | ||
'varint': 1, | ||
'i8': -10, | ||
@@ -46,3 +46,11 @@ 'u8': 8, | ||
Object.keys(typeArgs).forEach(function(index){ | ||
results[typeArgs[index].name] = getValue(typeArgs[index].type, results); | ||
const v=getValue(typeArgs[index].type, results); | ||
if(typeArgs[index].anon) { | ||
Object.keys(v).forEach(key => { | ||
results[key]=v[key]; | ||
}) | ||
} | ||
else { | ||
results[typeArgs[index].name] = v; | ||
} | ||
}); | ||
@@ -134,2 +142,9 @@ delete context[".."]; | ||
return getValue(typeArgs, context); | ||
}, | ||
'bitfield': function(typeArgs) { | ||
var results={}; | ||
Object.keys(typeArgs).forEach(function(index){ | ||
results[typeArgs[index].name] = 1; | ||
}); | ||
return results; | ||
} | ||
@@ -184,3 +199,3 @@ }; | ||
Object.keys(packets[state][direction].types).filter(function(packetName){return packetName!="packet"}).forEach(function(packetName){ | ||
packetInfo = packets[state][direction].types[packetName][1]; | ||
packetInfo = packets[state][direction].types[packetName]; | ||
packetInfo=packetInfo ? packetInfo : null; | ||
@@ -202,6 +217,3 @@ it(state + ","+(direction=="toServer" ? "Server" : "Client")+"Bound," + packetName, | ||
// empty object uses default values | ||
var packet = {}; | ||
packetInfo.forEach(function(field) { | ||
packet[field.name] = getValue(field.type, packet); | ||
}); | ||
var packet = getValue(packetInfo, {}); | ||
if(toServer) { | ||
@@ -208,0 +220,0 @@ serverClient.once(packetName, function(receivedPacket) { |
124148
2797