mirror of
https://github.com/PrismarineJS/node-minecraft-protocol.git
synced 2024-12-04 21:11:04 -05:00
Refactor FML|HS to use state machine
Instead of responding based on the packet type received, maintain a local state and ensure the correct packets are received. Should help avoid unexpected states/behavior. See: https://github.com/ORelio/Minecraft-Console-Client/pull/100/files#diff-65b97c02a9736311374109e22d30ca9cR297
This commit is contained in:
parent
8fd30f6af9
commit
6c33ec2856
1 changed files with 84 additions and 41 deletions
|
@ -1,5 +1,6 @@
|
||||||
var mc = require('minecraft-protocol');
|
var mc = require('minecraft-protocol');
|
||||||
var ProtoDef = require('protodef').ProtoDef;
|
var ProtoDef = require('protodef').ProtoDef;
|
||||||
|
var assert = require('assert');
|
||||||
|
|
||||||
if(process.argv.length < 4 || process.argv.length > 6) {
|
if(process.argv.length < 4 || process.argv.length > 6) {
|
||||||
console.log("Usage : node echo.js <host> <port> [<name>] [<password>]");
|
console.log("Usage : node echo.js <host> <port> [<name>] [<password>]");
|
||||||
|
@ -200,59 +201,101 @@ function writeAck(client, phase) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var FMLHandshakeClientState = {
|
||||||
|
START: 1,
|
||||||
|
WAITINGSERVERDATA: 2,
|
||||||
|
WAITINGSERVERCOMPLETE: 3,
|
||||||
|
PENDINGCOMPLETE: 4,
|
||||||
|
COMPLETE: 5,
|
||||||
|
};
|
||||||
|
|
||||||
function fmlHandshakeStep(client, data)
|
function fmlHandshakeStep(client, data)
|
||||||
{
|
{
|
||||||
var parsed = proto.parsePacketBuffer('FML|HS', data);
|
var parsed = proto.parsePacketBuffer('FML|HS', data);
|
||||||
console.log('FML|HS',parsed);
|
console.log('FML|HS',parsed);
|
||||||
|
|
||||||
if (parsed.data.discriminator === 'ServerHello') {
|
var fmlHandshakeState = client.fmlHandshakeState || FMLHandshakeClientState.START;
|
||||||
if (parsed.data.fmlProtocolVersion > 2) {
|
|
||||||
// TODO: support higher protocols, if they change
|
switch(fmlHandshakeState) {
|
||||||
|
case FMLHandshakeClientState.START:
|
||||||
|
{
|
||||||
|
assert.ok(parsed.data.discriminator === 'ServerHello', `expected ServerHello in START state, got ${parsed.data.discriminator}`);
|
||||||
|
if (parsed.data.fmlProtocolVersion > 2) {
|
||||||
|
// TODO: support higher protocols, if they change
|
||||||
|
}
|
||||||
|
|
||||||
|
client.write('custom_payload', {
|
||||||
|
channel: 'REGISTER',
|
||||||
|
data: new Buffer(['FML|HS', 'FML', 'FML|MP', 'FML', 'FORGE'].join('\0'))
|
||||||
|
});
|
||||||
|
|
||||||
|
var clientHello = proto.createPacketBuffer('FML|HS', {
|
||||||
|
discriminator: 'ClientHello',
|
||||||
|
fmlProtocolVersion: parsed.data.fmlProtocolVersion
|
||||||
|
});
|
||||||
|
|
||||||
|
client.write('custom_payload', {
|
||||||
|
channel: 'FML|HS',
|
||||||
|
data: clientHello
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('Sending client modlist');
|
||||||
|
var modList = proto.createPacketBuffer('FML|HS', {
|
||||||
|
discriminator: 'ModList',
|
||||||
|
mods: client.forgeMods || []
|
||||||
|
});
|
||||||
|
client.write('custom_payload', {
|
||||||
|
channel: 'FML|HS',
|
||||||
|
data: modList
|
||||||
|
});
|
||||||
|
writeAck(client, 2); // WAITINGSERVERDATA
|
||||||
|
client.fmlHandshakeState = FMLHandshakeClientState.WAITINGSERVERDATA;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
client.write('custom_payload', {
|
case FMLHandshakeClientState.WAITINGSERVERDATA:
|
||||||
channel: 'REGISTER',
|
{
|
||||||
data: new Buffer(['FML|HS', 'FML', 'FML|MP', 'FML', 'FORGE'].join('\0'))
|
assert.ok(parsed.data.discriminator === 'ModList', `expected ModList in WAITINGSERVERDATA state, got ${parsed.data.discriminator}`);
|
||||||
});
|
console.log('Server ModList:',parsed.data.mods);
|
||||||
|
// TODO: client/server check if mods compatible
|
||||||
var clientHello = proto.createPacketBuffer('FML|HS', {
|
client.fmlHandshakeState = FMLHandshakeClientState.WAITINGSERVERCOMPLETE;
|
||||||
discriminator: 'ClientHello',
|
break;
|
||||||
fmlProtocolVersion: parsed.data.fmlProtocolVersion
|
|
||||||
});
|
|
||||||
|
|
||||||
client.write('custom_payload', {
|
|
||||||
channel: 'FML|HS',
|
|
||||||
data: clientHello
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('Sending client modlist');
|
|
||||||
var modList = proto.createPacketBuffer('FML|HS', {
|
|
||||||
discriminator: 'ModList',
|
|
||||||
mods: client.forgeMods || []
|
|
||||||
});
|
|
||||||
client.write('custom_payload', {
|
|
||||||
channel: 'FML|HS',
|
|
||||||
data: modList
|
|
||||||
});
|
|
||||||
writeAck(client, 2); // WAITINGSERVERDATA
|
|
||||||
} else if (parsed.data.discriminator === 'ModList') {
|
|
||||||
console.log('Server ModList:',parsed.data.mods);
|
|
||||||
// TODO: client/server check if mods compatible
|
|
||||||
|
|
||||||
} else if (parsed.data.discriminator === 'RegistryData') {
|
|
||||||
console.log('RegistryData',parsed.data);
|
|
||||||
if (parsed.data.hasMore === false) {
|
|
||||||
console.log('LAST RegistryData');
|
|
||||||
|
|
||||||
writeAck(client, 3); // WAITINGSERVERCOMPLETE
|
|
||||||
}
|
}
|
||||||
} else if (parsed.data.discriminator === 'HandshakeAck') {
|
|
||||||
if (parsed.data.phase === 2) { // WAITINGCACK
|
case FMLHandshakeClientState.WAITINGSERVERCOMPLETE:
|
||||||
|
{
|
||||||
|
assert.ok(parsed.data.discriminator === 'RegistryData', `expected RegistryData in WAITINGSERVERCOMPLETE, got ${parsed.data.discriminator}`);
|
||||||
|
console.log('RegistryData',parsed.data);
|
||||||
|
// TODO: support <=1.7.10 single registry, https://github.com/ORelio/Minecraft-Console-Client/pull/100/files#diff-65b97c02a9736311374109e22d30ca9cR297
|
||||||
|
if (parsed.data.hasMore === false) {
|
||||||
|
console.log('LAST RegistryData');
|
||||||
|
|
||||||
|
writeAck(client, 3); // WAITINGSERVERCOMPLETE
|
||||||
|
client.fmlHandshakeState = FMLHandshakeClientState.PENDINGCOMPLETE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case FMLHandshakeClientState.PENDINGCOMPLETE:
|
||||||
|
{
|
||||||
|
assert.ok(parsed.data.discriminator === 'HandshakeAck', `expected HandshakeAck in PENDINGCOMPLETE, got ${parsed.data.discrimnator}`);
|
||||||
|
assert.ok(parsed.data.phase === 2, `expected HandshakeAck phase WAITINGACK, got ${parsed.data.phase}`);
|
||||||
writeAck(client, 4); // PENDINGCOMPLETE
|
writeAck(client, 4); // PENDINGCOMPLETE
|
||||||
} else if (parsed.data.phase === 3) { // COMPLETE
|
client.fmlHandshakeState = FMLHandshakeClientState.COMPLETE
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case FMLHandshakeClientState.COMPLETE:
|
||||||
|
{
|
||||||
|
assert.ok(parsed.data.phase === 3, `expected HandshakeAck phase COMPLETE, got ${parsed.data.phase}`);
|
||||||
|
|
||||||
writeAck(client, 5); // COMPLETE
|
writeAck(client, 5); // COMPLETE
|
||||||
console.log('HandshakeAck Complete!');
|
console.log('HandshakeAck Complete!');
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
console.error(`unexpected FML state ${fmlHandshakeState}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue