From de0ea4f3f63162915ffc7f9c0b616d4d726b9d1e Mon Sep 17 00:00:00 2001 From: roblabla Date: Tue, 24 Feb 2015 23:45:16 +0000 Subject: [PATCH] Add nbt support --- lib/protocol.js | 81 ++++++++++++++++++++++++++++++++++++++----------- package.json | 9 +++--- 2 files changed, 68 insertions(+), 22 deletions(-) diff --git a/lib/protocol.js b/lib/protocol.js index c8bbe5a..ee16f9c 100644 --- a/lib/protocol.js +++ b/lib/protocol.js @@ -1,6 +1,7 @@ var assert = require('assert'); var util = require('util'); var zlib = require('zlib'); +var nbt = require('nbt'); var STRING_MAX_LENGTH = 240; var SRV_STRING_MAX_LENGTH = 32767; @@ -853,6 +854,7 @@ var types = { // TODO : remove type-specific, replace with generic containers and arrays. 'position': [readPosition, writePosition, 8], 'slot': [readSlot, writeSlot, sizeOfSlot], + 'nbt': [readNbt, writeBuffer, sizeOfBuffer], 'entityMetadata': [readEntityMetadata, writeEntityMetadata, sizeOfEntityMetadata], }; @@ -957,6 +959,21 @@ function readEntityMetadata(buffer, offset) { } } +function readNbt(buffer, offset) { + buffer = buffer.slice(offset); + return nbt.parseUncompressed(buffer); +} + +function writeNbt(value, buffer, offset) { + var newbuf = nbt.writeUncompressed(value); + newbuf.copy(buffer, offset); + return offset + newbuf.length; +} + +function sizeOfNbt(value) { + return nbt.writeUncompressed(value).length; +} + function readString (buffer, offset) { var length = readVarInt(buffer, offset); if (!!!length) return null; @@ -1078,27 +1095,31 @@ function readPosition(buffer, offset) { } function readSlot(buffer, offset) { + var value = {}; var results = readShort(buffer, offset); if (! results) return null; - var blockId = results.value; + value.blockId = results.value; var cursor = offset + results.size; - if (blockId === -1) { + if (value.blockId === -1) { return { - value: { id: blockId }, + value: value, size: cursor - offset, }; } - var cursorEnd = cursor + 5; + var cursorEnd = cursor + 4; if (cursorEnd > buffer.length) return null; - var itemCount = buffer.readInt8(cursor); - var itemDamage = buffer.readInt16BE(cursor + 1); - var nbtDataSize = buffer.readInt16BE(cursor + 3); - if (nbtDataSize === -1) nbtDataSize = 0; - var nbtDataEnd = cursorEnd + nbtDataSize; - if (nbtDataEnd > buffer.length) return null; - var nbtData = buffer.slice(cursorEnd, nbtDataEnd); + value.itemCount = buffer.readInt8(cursor); + value.itemDamage = buffer.readInt16BE(cursor + 1); + var nbtData = buffer.readInt8(cursor + 3); + if (nbtData == 0) { + return { + value: value, + size: cursor + 4 - offset + } + } + var nbtData = readNbt(buffer, offset); return { value: { @@ -1112,7 +1133,13 @@ function readSlot(buffer, offset) { } function sizeOfSlot(value) { - return value.id === -1 ? 2 : 7 + value.nbtData.length; + if (value.id === -1) + return (2); + else if (!value.nbtData) { + return (6); + } else { + return (5 + sizeOfNbt(value.nbtData)); + } } function writePosition(value, buffer, offset) { @@ -1127,11 +1154,19 @@ function writeSlot(value, buffer, offset) { if (value.id === -1) return offset + 2; buffer.writeInt8(value.itemCount, offset + 2); buffer.writeInt16BE(value.itemDamage, offset + 3); - var nbtDataSize = value.nbtData.length; - if (nbtDataSize === 0) nbtDataSize = -1; // I don't know wtf mojang smokes - buffer.writeInt16BE(nbtDataSize, offset + 5); - value.nbtData.copy(buffer, offset + 7); - return offset + 7 + value.nbtData.length; + var nbtDataLen; + if (value.nbtData) + { + var newbuf = nbt.writeUncompressed(value.nbtData); + buffer.write(newbuf, offset + 5); + nbtDataLen = newbuf.length; + } + else + { + buffer.writeInt8(0, offset + 5); + nbtDataLen = 1; + } + return offset + 5 + nbtDataLen; } function sizeOfString(value) { @@ -1247,6 +1282,7 @@ function readContainer(buffer, offset, typeArgs, rootNode) { }; // BLEIGH. Huge hack because I have no way of knowing my current name. // TODO : either pass fieldInfo instead of typeArgs as argument (bleigh), or send name as argument (verybleigh). + // TODO : what I do inside of roblabla/Protocols is have each "frame" create a new empty slate with just a "super" object pointing to the parent. rootNode.this = results.value; for (var index in typeArgs.fields) { var readResults = read(buffer, offset, typeArgs.fields[index], rootNode); @@ -1370,8 +1406,17 @@ function read(buffer, cursor, fieldInfo, rootNodes) { error: new Error("missing data type: " + fieldInfo.type) }; } + try { var readResults = type[0](buffer, cursor, fieldInfo.typeArgs, rootNodes); - if (readResults.error) return { error: readResults.error }; + } catch (e) { + console.log("fieldInfo : " + JSON.stringify(fieldInfo)); + console.log("rootNodes : " + JSON.stringify(rootNodes)); + throw e; + } + if (readResults == null) { + throw new Error("Reader returned null : " + JSON.stringify(fieldInfo)); + } + if (readResults && readResults.error) return { error: readResults.error }; return readResults; } diff --git a/package.json b/package.json index 5e3af16..e53dbce 100644 --- a/package.json +++ b/package.json @@ -33,11 +33,12 @@ "batch": "~0.3.1" }, "dependencies": { - "node-rsa": "^0.1.53", - "superagent": "~0.10.0", - "buffer-equal": "0.0.0", "ansi-color": "0.2.1", - "node-uuid": "~1.4.1" + "buffer-equal": "0.0.0", + "nbt": "git://github.com/roblabla/nbt-js", + "node-rsa": "^0.1.53", + "node-uuid": "~1.4.1", + "superagent": "~0.10.0" }, "optionalDependencies": { "ursa": "~0.8.0"