从 Godot 解码 Variant 字节到 javascript 对象
Decoding Variant bytes from Godot to javascript object
我正在尝试将我认为是来自 Godot 的 Uint8 数组的字节数组反序列化为节点进程中的 javascript 对象。
我当前的实现是:
const message = Buffer.from(buffer.data, 'ascii');
console.log('message', message.toString('utf8'))
这是输出类似的东西:�a@
如何在节点进程中不使用 Godot 的 bytes2var 反序列化此对象?
var2bytes
使用值对类型信息进行编码。如果 PoolByteArray
中的数据表示 utf8 字符串,请使用 String 的方法 to_utf8()
而不是 var2bytes
.
字符串上还有 to_ascii()
方法。
var string = "hello"
var bytes = string.to_utf8()
如果您无权访问 Godot 中的序列化过程并且缓冲区有效负载旨在包含 ascii 或 utf8:
首先var2bytes
字符串编码很简单。前 4 个字节表示变体类型和编码标志。
后4个字节表示utf8编码字符串的长度
剩下的字节是utf8编码的字符串。可以在 4 字节偏移处填充缓冲区。
const lengthOffset = 4
const messageOffset = lengthOffset * 2
const messageLength = buffer.readUInt32LE(lengthOffset)
const messageEndOffset = messageLength + messageOffset
const message = buffer.slice(messageOffset, messageEndOffset)
console.log(message.toString('utf8'))
解码多种类型的变体数组
解码一系列变体更加复杂。您将必须为每种支持的类型重新实现 decode_variant。我将带您开始解码任意大小的整数、字符串和 Vector3 数组。
资源:
以下代码假定缓冲区有效。
// These values are from resource 2.
const variantEncodeMask = 0xFF
const variantEncodeFlag64 = 1 << 16
// These values are from resource 3.
const variantTypeInt = 2
const variantTypeString = 4
const variantTypeVector3 = 7
const variantTypeArray = 19
// Transcribed from resource 1.
function decodeVariant(buffer, _track = {offset: 0}) {
const typeAndFlags = buffer.readUInt32LE(_track.offset)
const type = typeAndFlags & variantEncodeMask
_track.offset += 4
// Buffer.slice does not copy memory. This makes the code a little easier to
// read since every read* doesn't need the _track.offset parameter.
const bufferSlice = buffer.slice(_track.offset)
let result
// The following switches on each type case. It's almost a one-to-one
// implementation of the decode_variant function defined in marshalls.cpp.
//
// The main difference here is that we use _track to track the buffer offset
// rather than using pointer arithmetic.
//
// Extend this by adding a case for the desired variant type. Follow godot's
// implementation and make sure to increment _track.offset by the correct
// byte count for every read* operation.
switch (type) {
case variantTypeInt:
if (typeAndFlags & variantEncodeFlag64) {
result = bufferSlice.readBigUInt64()
_track.offset += 8
} else {
result = bufferSlice.readUInt32LE()
_track.offset += 4
}
break
case variantTypeVector3:
result = {
x: bufferSlice.readFloatLE(),
y: bufferSlice.readFloatLE(4),
z: bufferSlice.readFloatLE(8)
}
_track.offset += 4 * 3
break
case variantTypeString:
const length = bufferSlice.readUInt32LE()
const offset = 4
const endOffset = length + offset
const payload = bufferSlice.slice(offset, endOffset)
let pad = 0
if (length % 4) {
pad = 4 - length % 4
}
result = payload.toString('utf8')
_track.offset += endOffset + pad
break
case variantTypeArray:
let count = bufferSlice.readUInt32LE()
count &= 0x7FFFFFFF // Don't know why array needs this.
_track.offset += 4
result = new Array(count)
for (let i = 0; i < count; i++) {
result[i] = decodeVariant(buffer, _track)
}
break
}
return result
}
我正在尝试将我认为是来自 Godot 的 Uint8 数组的字节数组反序列化为节点进程中的 javascript 对象。
我当前的实现是:
const message = Buffer.from(buffer.data, 'ascii');
console.log('message', message.toString('utf8'))
这是输出类似的东西:�a@
如何在节点进程中不使用 Godot 的 bytes2var 反序列化此对象?
var2bytes
使用值对类型信息进行编码。如果 PoolByteArray
中的数据表示 utf8 字符串,请使用 String 的方法 to_utf8()
而不是 var2bytes
.
字符串上还有 to_ascii()
方法。
var string = "hello"
var bytes = string.to_utf8()
如果您无权访问 Godot 中的序列化过程并且缓冲区有效负载旨在包含 ascii 或 utf8:
首先var2bytes
字符串编码很简单。前 4 个字节表示变体类型和编码标志。
后4个字节表示utf8编码字符串的长度
剩下的字节是utf8编码的字符串。可以在 4 字节偏移处填充缓冲区。
const lengthOffset = 4
const messageOffset = lengthOffset * 2
const messageLength = buffer.readUInt32LE(lengthOffset)
const messageEndOffset = messageLength + messageOffset
const message = buffer.slice(messageOffset, messageEndOffset)
console.log(message.toString('utf8'))
解码多种类型的变体数组
解码一系列变体更加复杂。您将必须为每种支持的类型重新实现 decode_variant。我将带您开始解码任意大小的整数、字符串和 Vector3 数组。
资源:
以下代码假定缓冲区有效。
// These values are from resource 2.
const variantEncodeMask = 0xFF
const variantEncodeFlag64 = 1 << 16
// These values are from resource 3.
const variantTypeInt = 2
const variantTypeString = 4
const variantTypeVector3 = 7
const variantTypeArray = 19
// Transcribed from resource 1.
function decodeVariant(buffer, _track = {offset: 0}) {
const typeAndFlags = buffer.readUInt32LE(_track.offset)
const type = typeAndFlags & variantEncodeMask
_track.offset += 4
// Buffer.slice does not copy memory. This makes the code a little easier to
// read since every read* doesn't need the _track.offset parameter.
const bufferSlice = buffer.slice(_track.offset)
let result
// The following switches on each type case. It's almost a one-to-one
// implementation of the decode_variant function defined in marshalls.cpp.
//
// The main difference here is that we use _track to track the buffer offset
// rather than using pointer arithmetic.
//
// Extend this by adding a case for the desired variant type. Follow godot's
// implementation and make sure to increment _track.offset by the correct
// byte count for every read* operation.
switch (type) {
case variantTypeInt:
if (typeAndFlags & variantEncodeFlag64) {
result = bufferSlice.readBigUInt64()
_track.offset += 8
} else {
result = bufferSlice.readUInt32LE()
_track.offset += 4
}
break
case variantTypeVector3:
result = {
x: bufferSlice.readFloatLE(),
y: bufferSlice.readFloatLE(4),
z: bufferSlice.readFloatLE(8)
}
_track.offset += 4 * 3
break
case variantTypeString:
const length = bufferSlice.readUInt32LE()
const offset = 4
const endOffset = length + offset
const payload = bufferSlice.slice(offset, endOffset)
let pad = 0
if (length % 4) {
pad = 4 - length % 4
}
result = payload.toString('utf8')
_track.offset += endOffset + pad
break
case variantTypeArray:
let count = bufferSlice.readUInt32LE()
count &= 0x7FFFFFFF // Don't know why array needs this.
_track.offset += 4
result = new Array(count)
for (let i = 0; i < count; i++) {
result[i] = decodeVariant(buffer, _track)
}
break
}
return result
}