homebridge-roborock-vacuum 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -0
- package/LICENSE +21 -0
- package/README.md +37 -0
- package/config.schema.json +31 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.js +39 -0
- package/dist/logger.js.map +1 -0
- package/dist/platform.js +167 -0
- package/dist/platform.js.map +1 -0
- package/dist/settings.js +8 -0
- package/dist/settings.js.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/vacuum_accessory.js +152 -0
- package/dist/vacuum_accessory.js.map +1 -0
- package/package.json +66 -0
- package/roborockLib/data/UserData +4 -0
- package/roborockLib/data/clientID +4 -0
- package/roborockLib/i18n/de/translations.json +188 -0
- package/roborockLib/i18n/en/translations.json +208 -0
- package/roborockLib/i18n/es/translations.json +188 -0
- package/roborockLib/i18n/fr/translations.json +188 -0
- package/roborockLib/i18n/it/translations.json +188 -0
- package/roborockLib/i18n/nl/translations.json +188 -0
- package/roborockLib/i18n/pl/translations.json +188 -0
- package/roborockLib/i18n/pt/translations.json +188 -0
- package/roborockLib/i18n/ru/translations.json +188 -0
- package/roborockLib/i18n/uk/translations.json +188 -0
- package/roborockLib/i18n/zh-cn/translations.json +188 -0
- package/roborockLib/lib/RRMapParser.js +447 -0
- package/roborockLib/lib/deviceFeatures.js +995 -0
- package/roborockLib/lib/localConnector.js +249 -0
- package/roborockLib/lib/map/map.html +110 -0
- package/roborockLib/lib/map/zones.js +713 -0
- package/roborockLib/lib/mapCreator.js +692 -0
- package/roborockLib/lib/message.js +223 -0
- package/roborockLib/lib/messageQueueHandler.js +87 -0
- package/roborockLib/lib/roborockPackageHelper.js +116 -0
- package/roborockLib/lib/roborock_mqtt_connector.js +349 -0
- package/roborockLib/lib/sniffing/mitmproxy_roborock.py +300 -0
- package/roborockLib/lib/vacuum.js +636 -0
- package/roborockLib/roborockAPI.js +1365 -0
- package/roborockLib/test.js +31 -0
- package/roborockLib/userdata.json +24 -0
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const crypto = require("crypto");
|
|
4
|
+
|
|
5
|
+
const TYPES = {
|
|
6
|
+
CHARGER_LOCATION: 1,
|
|
7
|
+
IMAGE: 2,
|
|
8
|
+
PATH: 3,
|
|
9
|
+
GOTO_PATH: 4,
|
|
10
|
+
GOTO_PREDICTED_PATH: 5,
|
|
11
|
+
CURRENTLY_CLEANED_ZONES: 6,
|
|
12
|
+
GOTO_TARGET: 7,
|
|
13
|
+
ROBOT_POSITION: 8,
|
|
14
|
+
FORBIDDEN_ZONES: 9,
|
|
15
|
+
VIRTUAL_WALLS: 10,
|
|
16
|
+
CURRENTLY_CLEANED_BLOCKS: 11,
|
|
17
|
+
NO_MOP_ZONE: 12,
|
|
18
|
+
OBSTACLES: 13,
|
|
19
|
+
IGNORED_OBSTACLES: 14,
|
|
20
|
+
OBSTACLES2: 15,
|
|
21
|
+
IGNORED_OBSTACLES2: 16,
|
|
22
|
+
CARPET_MAP: 17,
|
|
23
|
+
MOP_PATH: 18,
|
|
24
|
+
CARPET_FORBIDDEN_ZONE: 19,
|
|
25
|
+
SMART_ZONE_PATH_TYPE: 20,
|
|
26
|
+
SMART_ZONE: 21,
|
|
27
|
+
CUSTOM_CARPET: 22,
|
|
28
|
+
CL_FORBIDDEN_ZONES: 23,
|
|
29
|
+
FLOOR_MAP: 24,
|
|
30
|
+
FURNITURES: 25,
|
|
31
|
+
DOCK_TYPE: 26,
|
|
32
|
+
ENEMIES: 27,
|
|
33
|
+
DS_FORBIDDEN_ZONES: 28, // WTF IS DS???
|
|
34
|
+
STUCK_POINTS: 29, // not currently processed
|
|
35
|
+
CLF_FORBIDDEN_ZONES: 30, // WTF IS CLF???
|
|
36
|
+
SMART_DS: 31, // not currently processed
|
|
37
|
+
FLOOR_DIRECTION: 32, // not 100% sure this FLOOR_DIRECTION but Roborock defined this as flDirec
|
|
38
|
+
DATE: 33, // not currently processed
|
|
39
|
+
NONCEDATA: 34,
|
|
40
|
+
EXT_ZONES: 36, // not currently processed
|
|
41
|
+
PATROL: 37, // not currently processed
|
|
42
|
+
PET_PATROL: 38, // not currently processed
|
|
43
|
+
MODE_CARPET: 39, // not currently processed
|
|
44
|
+
STROY_PT: 41, // not currently processed
|
|
45
|
+
DIRTY_RECT: 42, // not currently processed
|
|
46
|
+
IGNORE_DIRTY_RECT: 43, // not currently processed
|
|
47
|
+
BRUSH_PT: 44, // not currently processed
|
|
48
|
+
DIRTY_NEW: 45, // not currently processed
|
|
49
|
+
DIGEST: 1024,
|
|
50
|
+
};
|
|
51
|
+
const TYPES_REVERSE = Object.fromEntries(Object.entries(TYPES).map(([key, value]) => [value, key]));
|
|
52
|
+
|
|
53
|
+
const OFFSETS = {
|
|
54
|
+
HLENGTH: 0x02,
|
|
55
|
+
LENGTH: 0x04,
|
|
56
|
+
TYPE_COUNT: 0x08,
|
|
57
|
+
TARGET_X: 0x08,
|
|
58
|
+
ANGLE: 0x10,
|
|
59
|
+
PATH: 0x14,
|
|
60
|
+
TARGET_Y: 0x0a,
|
|
61
|
+
BLOCKS: 0x0c,
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
class RRMapParser {
|
|
65
|
+
constructor(adapter) {
|
|
66
|
+
this.adapter = adapter;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
BytesToInt(buffer, offset, len) {
|
|
70
|
+
let result = 0;
|
|
71
|
+
|
|
72
|
+
for (let i = 0; i < len; i++) {
|
|
73
|
+
result |= (0x000000FF & parseInt(buffer[i + offset])) << 8 * i;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async parsedata(buf) {
|
|
80
|
+
const metaData = this.PARSE(buf);
|
|
81
|
+
if (!metaData.map_index) {
|
|
82
|
+
this.adapter.log.error(`RRMapParser: Failed to parse map data. map_index was missing`);
|
|
83
|
+
return {};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (metaData.SHA1 != metaData.expectedSHA1) {
|
|
87
|
+
this.adapter.log.error(`Invalid map hash!`);
|
|
88
|
+
return {};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
let dataPosition = 0x14; // Skip header
|
|
92
|
+
|
|
93
|
+
const result = {};
|
|
94
|
+
result.metaData = metaData;
|
|
95
|
+
|
|
96
|
+
while (dataPosition < metaData.data_length) {
|
|
97
|
+
const type = buf.readUInt16LE(dataPosition);
|
|
98
|
+
const hlength = buf.readUInt16LE(dataPosition + OFFSETS.HLENGTH);
|
|
99
|
+
const length = buf.readUInt32LE(dataPosition + OFFSETS.LENGTH);
|
|
100
|
+
|
|
101
|
+
const blockBuffer = buf.slice(dataPosition, dataPosition + hlength + length);
|
|
102
|
+
const [offset1, offset2] = this.getTwoByteOffsets(blockBuffer);
|
|
103
|
+
|
|
104
|
+
// this.adapter.log.debug("Known values: type=" + type + ", hlength=" + hlength + ", length=" + length);
|
|
105
|
+
|
|
106
|
+
if (TYPES_REVERSE[type]) {
|
|
107
|
+
|
|
108
|
+
// this.adapter.log.debug("Test length: " + TYPES_REVERSE[type] + " " + length);
|
|
109
|
+
// if (length < 100) this.adapter.log.debug("Test data type: " + TYPES_REVERSE[type] + " " + buf.toString("hex", dataPosition, dataPosition + length));
|
|
110
|
+
|
|
111
|
+
// this.adapter.log.warn(`Block type buffer data: ${TYPES_REVERSE[type]} ${JSON.stringify(blockBuffer)}`);
|
|
112
|
+
// this.adapter.log.warn(`Block type hex data: ${TYPES_REVERSE[type]} ${blockBuffer.toString("hex")}`);
|
|
113
|
+
|
|
114
|
+
switch (type) {
|
|
115
|
+
case TYPES.ROBOT_POSITION:
|
|
116
|
+
case TYPES.CHARGER_LOCATION: {
|
|
117
|
+
const position = this.getXYPositions(blockBuffer, offset1, offset2);
|
|
118
|
+
const angle = length >= 12 ? this.getAngle(blockBuffer) : 0; // gen3+
|
|
119
|
+
|
|
120
|
+
result[TYPES_REVERSE[type]] = {
|
|
121
|
+
position,
|
|
122
|
+
angle,
|
|
123
|
+
};
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
case TYPES.IMAGE: {
|
|
127
|
+
const offset = this.getSingleByteOffset(blockBuffer);
|
|
128
|
+
const [left, top, width, height] = this.getMapSizes(blockBuffer, offset1);
|
|
129
|
+
|
|
130
|
+
let parameters = {};
|
|
131
|
+
parameters = {
|
|
132
|
+
segments: {
|
|
133
|
+
count: hlength > 24 ? this.getCount(blockBuffer) : 0,
|
|
134
|
+
id: [],
|
|
135
|
+
},
|
|
136
|
+
position: {
|
|
137
|
+
top: top,
|
|
138
|
+
left: left,
|
|
139
|
+
},
|
|
140
|
+
dimensions: {
|
|
141
|
+
height: height,
|
|
142
|
+
width: width,
|
|
143
|
+
},
|
|
144
|
+
pixels: {
|
|
145
|
+
floor: [],
|
|
146
|
+
obstacle: [],
|
|
147
|
+
segments: [],
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
if (parameters.dimensions.height > 0 && parameters.dimensions.width > 0) {
|
|
152
|
+
let segmenetID = 0;
|
|
153
|
+
|
|
154
|
+
for (let i = 0; i < length; i++) {
|
|
155
|
+
const pixelType = this.getPixelType(buf, dataPosition + i + offset1);
|
|
156
|
+
|
|
157
|
+
if (pixelType == 1) {
|
|
158
|
+
// Obstacle
|
|
159
|
+
parameters.pixels.obstacle.push(i);
|
|
160
|
+
} else if (pixelType != 0) {
|
|
161
|
+
// Floor
|
|
162
|
+
parameters.pixels.floor.push(i);
|
|
163
|
+
|
|
164
|
+
segmenetID = (buf.readUInt8(offset + dataPosition + i) & 248) >> 3;
|
|
165
|
+
if (segmenetID !== 0) {
|
|
166
|
+
if (!parameters.segments.id.includes(segmenetID)) parameters.segments.id.push(segmenetID); // Add segment ID to array if it doesn't exist
|
|
167
|
+
|
|
168
|
+
parameters.pixels.segments.push(i | (segmenetID << 21)); // Add segment ID to pixel
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
result[TYPES_REVERSE[type]] = parameters;
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
case TYPES.CARPET_MAP: {
|
|
177
|
+
result[TYPES_REVERSE[type]] = [];
|
|
178
|
+
|
|
179
|
+
for (let i = 0; i < length; i++) {
|
|
180
|
+
// Only add the pixel index to the carpet array if it is a carpet pixel
|
|
181
|
+
if (this.getPixelType(buf, dataPosition + i) == 1) {
|
|
182
|
+
result[TYPES_REVERSE[type]].push(i);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
break;
|
|
187
|
+
}
|
|
188
|
+
case TYPES.MOP_PATH: {
|
|
189
|
+
result[TYPES_REVERSE[type]] = [];
|
|
190
|
+
|
|
191
|
+
for (let i = 0; i < length; i++) {
|
|
192
|
+
result[TYPES_REVERSE[type]].push(...this.readUInt8(buf, dataPosition + i, OFFSETS.PATH, 1));
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
197
|
+
case TYPES.PATH:
|
|
198
|
+
case TYPES.GOTO_PATH:
|
|
199
|
+
case TYPES.GOTO_PREDICTED_PATH: {
|
|
200
|
+
const pathType = TYPES_REVERSE[type];
|
|
201
|
+
result[pathType] = {
|
|
202
|
+
current_angle: this.getAngle(blockBuffer),
|
|
203
|
+
points: [],
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
for (let i = 0; i < length; i = i + 4) {
|
|
207
|
+
result[pathType].points.push(this.getPointInPath(buf, dataPosition + i));
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (result[pathType].points.length >= 2) {
|
|
211
|
+
const lastPoint = result[pathType].points[result[pathType].points.length - 1];
|
|
212
|
+
const secondLastPoint = result[pathType].points[result[pathType].points.length - 2];
|
|
213
|
+
|
|
214
|
+
result[pathType].current_angle =
|
|
215
|
+
(Math.atan2(
|
|
216
|
+
// Calculate the angle between the last two points
|
|
217
|
+
lastPoint[1] - secondLastPoint[1],
|
|
218
|
+
lastPoint[0] - secondLastPoint[0]
|
|
219
|
+
) *
|
|
220
|
+
180) /
|
|
221
|
+
Math.PI;
|
|
222
|
+
}
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
case TYPES.GOTO_TARGET:
|
|
227
|
+
result[TYPES_REVERSE[type]] = this.getGoToTarget(blockBuffer);
|
|
228
|
+
break;
|
|
229
|
+
|
|
230
|
+
case TYPES.CURRENTLY_CLEANED_ZONES:
|
|
231
|
+
case TYPES.VIRTUAL_WALLS: {
|
|
232
|
+
const wallCount = buf.readUInt32LE(0x08 + dataPosition);
|
|
233
|
+
result[TYPES_REVERSE[type]] = [];
|
|
234
|
+
|
|
235
|
+
for (let i = 0; i < wallCount; i++) {
|
|
236
|
+
const wallDataPosition = dataPosition + i * 8; // 8 Bytes pro Wand
|
|
237
|
+
result[TYPES_REVERSE[type]].push(this.readUInt16LE(buf, wallDataPosition, offset1, 4));
|
|
238
|
+
}
|
|
239
|
+
break;
|
|
240
|
+
}
|
|
241
|
+
case TYPES.FORBIDDEN_ZONES:
|
|
242
|
+
case TYPES.NO_MOP_ZONE:
|
|
243
|
+
case TYPES.CARPET_FORBIDDEN_ZONE:
|
|
244
|
+
case TYPES.DS_FORBIDDEN_ZONES:
|
|
245
|
+
case TYPES.CLF_FORBIDDEN_ZONES:
|
|
246
|
+
case TYPES.MODE_CARPET: {
|
|
247
|
+
const zoneCount = this.getCount(blockBuffer);
|
|
248
|
+
result[TYPES_REVERSE[type]] = [];
|
|
249
|
+
for (let i = 0; i < zoneCount; i++) {
|
|
250
|
+
const zoneDataPosition = dataPosition + i * 16; // 16 Bytes pro Zone
|
|
251
|
+
result[TYPES_REVERSE[type]].push(this.getForbiddenZone(buf, zoneDataPosition, offset1));
|
|
252
|
+
}
|
|
253
|
+
break;
|
|
254
|
+
}
|
|
255
|
+
case TYPES.OBSTACLES2:
|
|
256
|
+
result[TYPES_REVERSE[type]] = this.extractObstacles(blockBuffer, offset1);
|
|
257
|
+
break;
|
|
258
|
+
case TYPES.CURRENTLY_CLEANED_BLOCKS: {
|
|
259
|
+
const blockCount = this.getCount(blockBuffer);
|
|
260
|
+
result[TYPES_REVERSE[type]] = [];
|
|
261
|
+
|
|
262
|
+
for (let i = 0; i < blockCount; i++) {
|
|
263
|
+
result[TYPES_REVERSE[type]].push(buf.readUInt8(OFFSETS.BLOCKS + dataPosition + i));
|
|
264
|
+
}
|
|
265
|
+
break;
|
|
266
|
+
}
|
|
267
|
+
case TYPES.NONCEDATA:
|
|
268
|
+
result[TYPES_REVERSE[type]] = this.getNonceData(blockBuffer);
|
|
269
|
+
this.adapter.log.debug(`Block type 34 debug: ${JSON.stringify(result[TYPES_REVERSE[type]])}`);
|
|
270
|
+
break;
|
|
271
|
+
}
|
|
272
|
+
} else {
|
|
273
|
+
this.adapter.log.warn(`Unknown block type! Please report this to the developer. Block type is: ${type} and a length of ${length}`);
|
|
274
|
+
this.adapter.log.warn(`Unknown block type hex data: ${TYPES_REVERSE[type]} ${blockBuffer.toString("hex")}`);
|
|
275
|
+
this.adapter.log.warn(`Unknown block type buffer data: ${TYPES_REVERSE[type]} ${JSON.stringify(blockBuffer)}`);
|
|
276
|
+
}
|
|
277
|
+
dataPosition = dataPosition + length + hlength;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
return result;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
*
|
|
285
|
+
* @param mapBuf {Buffer} Should contain map in RRMap Format
|
|
286
|
+
* @return {object}
|
|
287
|
+
*/
|
|
288
|
+
PARSE(mapBuf) {
|
|
289
|
+
if (mapBuf && mapBuf[0x00] === 0x72 && mapBuf[0x01] === 0x72) {
|
|
290
|
+
return {
|
|
291
|
+
header_length: mapBuf.readUInt16LE(OFFSETS.HLENGTH),
|
|
292
|
+
data_length: mapBuf.readUInt32LE(OFFSETS.LENGTH),
|
|
293
|
+
version: {
|
|
294
|
+
major: mapBuf.readUInt16LE(0x08),
|
|
295
|
+
minor: mapBuf.readUInt16LE(0x0a),
|
|
296
|
+
},
|
|
297
|
+
map_index: mapBuf.readUInt32LE(0x0C),
|
|
298
|
+
map_sequence: mapBuf.readUInt32LE(0x10),
|
|
299
|
+
SHA1: crypto.createHash("sha1").update(Uint8Array.prototype.slice.call(mapBuf, 0, mapBuf.length - 20)).digest("hex"),
|
|
300
|
+
expectedSHA1: Buffer.from(Uint8Array.prototype.slice.call(mapBuf, mapBuf.length - 20)).toString("hex"),
|
|
301
|
+
};
|
|
302
|
+
} else {
|
|
303
|
+
return {};
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
extractObstacles(buf, offset) {
|
|
308
|
+
const obstacleCount = this.getCount(buf);
|
|
309
|
+
const obstacles = [];
|
|
310
|
+
|
|
311
|
+
for (let i = 0; i < obstacleCount * 28; i += 28) {
|
|
312
|
+
const obstacle = [
|
|
313
|
+
buf.readUInt16LE(offset + i), // x
|
|
314
|
+
buf.readUInt16LE(offset + i + 2), // y
|
|
315
|
+
buf.readUInt16LE(offset + i + 4), // obstacle type
|
|
316
|
+
buf.readUInt16LE(offset + i + 6), // confidence level
|
|
317
|
+
buf.readUInt16LE(offset + i + 8), // unknown
|
|
318
|
+
buf.readUInt16LE(offset + i + 10), // unknown
|
|
319
|
+
buf.toString("utf-8", offset + i + 12, offset + i + 12 + 16), // photo id
|
|
320
|
+
];
|
|
321
|
+
obstacles.push(obstacle);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
return obstacles;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
getXYPositions(buf, xOffset, yOffset) {
|
|
328
|
+
const xPosition = buf.readInt32LE(xOffset);
|
|
329
|
+
const yPosition = buf.readInt32LE(yOffset);
|
|
330
|
+
|
|
331
|
+
return [xPosition, yPosition];
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
getMapSizes(buf, offset) {
|
|
335
|
+
const top = buf.readInt32LE(offset - 0x10);
|
|
336
|
+
const left = buf.readInt32LE(offset - 0x0c);
|
|
337
|
+
const height = buf.readInt32LE(offset - 0x08);
|
|
338
|
+
const width = buf.readInt32LE(offset - 0x04);
|
|
339
|
+
|
|
340
|
+
return [left, top, width, height];
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
getPointInPath(buf, dataPosition) {
|
|
344
|
+
const result = [];
|
|
345
|
+
for (let i = 0; i < 2; i++) {
|
|
346
|
+
result.push(buf.readUInt16LE(dataPosition + OFFSETS.PATH + i * 2));
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
return result;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
getCount(buf) {
|
|
353
|
+
return buf.readUInt32LE(OFFSETS.TYPE_COUNT);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
getPixelType(buf, dataPosition) {
|
|
357
|
+
// Get the pixel type with bitwise AND operation of 0x07
|
|
358
|
+
return buf.readUInt8(dataPosition) & 0x07;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
getAngle(buf) {
|
|
362
|
+
return buf.readInt32LE(OFFSETS.ANGLE);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
getGoToTarget(buf) {
|
|
366
|
+
return [buf.readUInt16LE(OFFSETS.TARGET_X), buf.readUInt16LE(OFFSETS.TARGET_Y)];
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
getForbiddenZone(buf, dataPosition, offset) {
|
|
370
|
+
return this.readUInt16LE(buf, dataPosition, offset, 8);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
getSingleByteOffset(buf) {
|
|
374
|
+
return buf.readUInt8(2);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
getTwoByteOffsets(buf) {
|
|
378
|
+
return [buf.readUInt8(2), buf.readUInt8(4)];
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
getDatatype(buf, offset) {
|
|
382
|
+
// Get the first byte of the block
|
|
383
|
+
const byte = buf[offset];
|
|
384
|
+
|
|
385
|
+
// Check the byte value
|
|
386
|
+
if (byte >= 0x00 && byte <= 0xff) {
|
|
387
|
+
// It's an unsigned byte
|
|
388
|
+
return "UInt8";
|
|
389
|
+
} else if (byte >= 0x00 && byte <= 0xffff) {
|
|
390
|
+
// It's an unsigned 16-bit little-endian integer
|
|
391
|
+
return "UInt16LE";
|
|
392
|
+
} else if (byte >= 0x00 && byte <= 0xffffffff) {
|
|
393
|
+
// It's an unsigned 32-bit little-endian integer
|
|
394
|
+
return "UInt32LE";
|
|
395
|
+
} else {
|
|
396
|
+
// It's an unknown type
|
|
397
|
+
return "Unknown";
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
getNonceData(buf) {
|
|
402
|
+
const sections = [];
|
|
403
|
+
|
|
404
|
+
for (let i = 12; i < buf.length; i += 5) {
|
|
405
|
+
const type = buf[i];
|
|
406
|
+
const unixTime = buf.readUInt32LE(i + 1);
|
|
407
|
+
|
|
408
|
+
sections.push({ type, unixTime });
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
return sections;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
readUInt16LE(buf, dataPosition, offset, count) {
|
|
415
|
+
const result = [];
|
|
416
|
+
for (let j = 0; j < count; j++) {
|
|
417
|
+
result.push(buf.readUInt16LE(dataPosition + offset + j * 2));
|
|
418
|
+
}
|
|
419
|
+
return result;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
readInt32LE(buf, dataPosition, offset, count) {
|
|
423
|
+
const array = [];
|
|
424
|
+
for (let j = 0; j < count; j++) {
|
|
425
|
+
array.push(buf.readInt32LE(offset + dataPosition + j * 4));
|
|
426
|
+
}
|
|
427
|
+
return array;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
readUInt32LE(buf, dataPosition, offset, count) {
|
|
431
|
+
const array = [];
|
|
432
|
+
for (let j = 0; j < count; j++) {
|
|
433
|
+
array.push(buf.readUInt32LE(offset + dataPosition + j * 4));
|
|
434
|
+
}
|
|
435
|
+
return array;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
readUInt8(buf, dataPosition, offset, count) {
|
|
439
|
+
const array = [];
|
|
440
|
+
for (let j = 0; j < count; j++) {
|
|
441
|
+
array.push(buf.readUInt8(offset + dataPosition + j));
|
|
442
|
+
}
|
|
443
|
+
return array;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
module.exports = RRMapParser;
|