From 79ded321bf9b0c4f50c0590cdc3386ba1ebf11b0 Mon Sep 17 00:00:00 2001 From: roblabla Date: Thu, 27 Aug 2015 11:36:07 +0000 Subject: [PATCH] Add extend type support --- package.json | 5 ++- src/browser.js | 2 +- src/client.js | 2 +- src/datatypes/minecraft.js | 72 ++++-------------------------------- src/index.js | 2 +- src/protocol.js | 58 ++++++++++++++++++++++++++++- src/transforms/serializer.js | 5 ++- test/test.js | 14 ++++--- 8 files changed, 81 insertions(+), 79 deletions(-) diff --git a/package.json b/package.json index f51dbf1..b2bae50 100644 --- a/package.json +++ b/package.json @@ -42,12 +42,13 @@ "dependencies": { "babel-runtime": "^5.4.4", "buffer-equal": "0.0.0", + "lodash.reduce": "^3.1.2", + "minecraft-data": "0.8.1", "node-uuid": "~1.4.1", "prismarine-nbt": "0.0.1", "readable-stream": "^1.1.0", "superagent": "~0.10.0", - "ursa-purejs": "0.0.3", - "minecraft-data": "0.7.0" + "ursa-purejs": "0.0.3" }, "optionalDependencies": { "ursa": "~0.8.0" diff --git a/src/browser.js b/src/browser.js index 1d3a9a3..f0cc6f6 100644 --- a/src/browser.js +++ b/src/browser.js @@ -1,5 +1,5 @@ var version = require('./version'); -var packets = require('minecraft-data')(version.majorVersion).protocol; +var packets = require('minecraft-data')(version.majorVersion).protocol.states; var readPackets = require("./packets").readPackets; var packetIndexes = readPackets(packets, states); var utils = require("./utils"); diff --git a/src/client.js b/src/client.js index 7cfecc9..12d2c97 100644 --- a/src/client.js +++ b/src/client.js @@ -8,7 +8,7 @@ var EventEmitter = require('events').EventEmitter , states = serializer.states ; var version = require('./version'); -var packets = require('minecraft-data')(version.majorVersion).protocol; +var packets = require('minecraft-data')(version.majorVersion).protocol.states; var readPackets = require("./packets").readPackets; var packetIndexes = readPackets(packets, states); diff --git a/src/datatypes/minecraft.js b/src/datatypes/minecraft.js index 54979a2..8909b8a 100644 --- a/src/datatypes/minecraft.js +++ b/src/datatypes/minecraft.js @@ -147,56 +147,11 @@ function sizeOfRestBuffer(value) { return value.length; } -var entityMetadataTypes = { - 0: {type: 'byte'}, - 1: {type: 'short'}, - 2: {type: 'int'}, - 3: {type: 'float'}, - 4: {type: 'string'}, - 5: {type: 'slot'}, - 6: { - type: 'container', typeArgs: { - fields: [ - {name: 'x', type: 'int'}, - {name: 'y', type: 'int'}, - {name: 'z', type: 'int'} - ] - } - }, - 7: { - type: 'container', typeArgs: { - fields: [ - {name: 'pitch', type: 'float'}, - {name: 'yaw', type: 'float'}, - {name: 'roll', type: 'float'} - ] - } - } -}; - -// maps string type name to number -var entityMetadataTypeBytes = {}; -for(var n in entityMetadataTypes) { - if(!entityMetadataTypes.hasOwnProperty(n)) continue; - - entityMetadataTypeBytes[entityMetadataTypes[n].type] = n; -} - -// container is ambiguous -function findByte(type,value) -{ - if(type!="container") - return entityMetadataTypeBytes[type]; - return value["x"]===undefined ? 7 : 6; -} - - -function readEntityMetadata(buffer, offset) { +function readEntityMetadata(buffer, offset, typeArgs, context) { var cursor = offset; var metadata = []; var item, key, type, results, reader, typeName, dataType; while(true) { - if(cursor + 1 > buffer.length) return null; item = buffer.readUInt8(cursor); cursor += 1; if(item === 0x7f) { @@ -207,46 +162,33 @@ function readEntityMetadata(buffer, offset) { } key = item & 0x1f; type = item >> 5; - dataType = entityMetadataTypes[type]; - typeName = dataType.type; - //debug("Reading entity metadata type " + dataType + " (" + ( typeName || "unknown" ) + ")"); - if(!dataType) { - return { - error: new Error("unrecognized entity metadata type " + type) - } - } - results = this.read(buffer, cursor, dataType, {}); - if(!results) return null; + var results = this.read(buffer, cursor, ["entityMetadataItem", { "compareTo": "type" }], { type }); metadata.push({ - key: key, + key, + type, value: results.value, - type: typeName, }); cursor += results.size; } } - function writeEntityMetadata(value, buffer, offset) { var self = this; value.forEach(function(item) { - var type = findByte(item.type,item.value); - var headerByte = (type << 5) | item.key; - buffer.writeUInt8(headerByte, offset); + buffer.writeUInt8(item.type << 5 | item.key, offset); offset += 1; - offset = self.write(item.value, buffer, offset, entityMetadataTypes[type], {}); + offset = self.write(item.value, buffer, offset, ["entityMetadataItem", { "compareTo": "type" }], item); }); buffer.writeUInt8(0x7f, offset); return offset + 1; } - function sizeOfEntityMetadata(value) { var size = 1 + value.length; var item; for(var i = 0; i < value.length; ++i) { item = value[i]; - size += this.sizeOf(item.value, entityMetadataTypes[findByte(item.type,item.value)], {}); + size += this.sizeOf(item.value, ["entityMetadataItem", { "compareTo": "type" }], item); } return size; } diff --git a/src/index.js b/src/index.js index 7b4169a..ff5270b 100644 --- a/src/index.js +++ b/src/index.js @@ -4,7 +4,7 @@ var Yggdrasil = require('./yggdrasil.js'); var serializer = require("./transforms/serializer"); var utils = require("./utils"); var version = require("./version"); -var packets = require('minecraft-data')(version.majorVersion).protocol; +var packets = require('minecraft-data')(version.majorVersion).protocol.states; var readPackets = require("./packets").readPackets; var packetIndexes = readPackets(packets, serializer.states); var createClient = require("./createClient"); diff --git a/src/protocol.js b/src/protocol.js index 50327d6..0dd1a35 100644 --- a/src/protocol.js +++ b/src/protocol.js @@ -1,13 +1,69 @@ var { getFieldInfo } = require('./utils'); +var reduce = require('lodash.reduce'); function NMProtocols() { this.types = {}; } +function isFieldInfo(type) { + return typeof type === "string" + || (Array.isArray(type) && typeof type[0] === "string") + || type.type; +} + NMProtocols.prototype.addType = function(name, functions) { - this.types[name] = functions; + if (functions === "native") + return; + else if (isFieldInfo(functions)) { + var fieldInfo = getFieldInfo(functions); + this.types[name] = extendType(this.types[fieldInfo.type], fieldInfo.typeArgs); + } + else + this.types[name] = functions; }; +function findArgs(acc, v, k) { + if (typeof v === "string" && v.charAt(0) === '$') + acc.push({ "path": k, "val": v.substr(1) }); + else if (Array.isArray(v) || typeof v === "object") + acc = acc.concat(reduce(v, findArgs, []).map((v) => ({ "path": k + "." + v.path, "val": v.val }))); + return acc; +} + +function setField(path, val, into) { + var c = path.split('.').reverse(); + while (c.length > 1) { + into = into[c.pop()]; + } + into[c.pop()] = val; +} + +function extendType(functions, defaultTypeArgs) { + var argPos = reduce(defaultTypeArgs, findArgs, []); + return [function read(buffer, offset, typeArgs, context) { + var args = JSON.parse(JSON.stringify(defaultTypeArgs)); + argPos.forEach((v) => { + setField(v.path, typeArgs[v.val], args); + }); + return functions[0].call(this, buffer, offset, args, context); + }, function write(value, buffer, offset, typeArgs, context) { + var args = JSON.parse(JSON.stringify(defaultTypeArgs)); + argPos.forEach((v) => { + setField(v.path, typeArgs[v.val], args); + }); + return functions[1].call(this, value, buffer, offset, args, context); + }, function sizeOf(value, typeArgs, context) { + var args = JSON.parse(JSON.stringify(defaultTypeArgs)); + argPos.forEach((v) => { + setField(v.path, typeArgs[v.val], args); + }); + if (typeof functions[2] === "function") + return functions[2].call(this, value, args, context); + else + return functions[2]; + }]; +} + NMProtocols.prototype.addTypes = function(types) { var self = this; Object.keys(types).forEach(function(name) { diff --git a/src/transforms/serializer.js b/src/transforms/serializer.js index 9859f99..0ecd162 100644 --- a/src/transforms/serializer.js +++ b/src/transforms/serializer.js @@ -44,13 +44,14 @@ proto.addTypes(minecraft); proto.addTypes(structures); proto.addTypes(conditional); - module.exports.types = proto.types; var version = require('../version'); var packets = require('minecraft-data')(version.majorVersion).protocol; +proto.addTypes(packets.types); + var readPackets = require("../packets").readPackets; -var packetIndexes = readPackets(packets, states); +var packetIndexes = readPackets(packets.states, states); var packetFields = packetIndexes.packetFields; var packetNames = packetIndexes.packetNames; diff --git a/test/test.js b/test/test.js index 854c9a9..d8bc1f9 100644 --- a/test/test.js +++ b/test/test.js @@ -115,12 +115,14 @@ var values = { }, 'long': [0, 1], 'entityMetadata': [ - {key: 17, value: 0, type: 'int'}, - {key: 0, value: 0, type: 'byte'}, - {key: 16, value: 0, type: 'byte'}, - {key: 1, value: 300, type: 'short'}, - {key: 19, value: 0, type: 'int'}, - {key: 18, value: 1, type: 'int'}, + {key: 17, value: 0, type: 0}, + {key: 0, value: 257, type: 1}, + {key: 16, value: 626, type: 2}, + {key: 1, value: 0.15, type: 3}, + {key: 19, value: "Some string", type: 4}, + //{key: 18, value: {}, type: 5}, Slot is a pain, I'll do it later + {key: 18, value: { x: 0, y: 0, z: 0 }, type: 6}, + {key: 18, value: { pitch: 0.5, yaw: 0.7, roll: 12.4 }, type: 7}, ], 'objectData': { intField: 9,