Skip to content

Commit a8b2641

Browse files
SuperGamerTrongithub-actions[bot]extremeheat
authored
1.21.9: Add lpvec3 data type (#1453)
* Update to version 1.21.10 * Update ci.yml * Update ci.yml * Update packetTest.js types * Handle code_of_conduct packets * Implement lpVec3 * Update ci.yml --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: extremeheat <extreme@protonmail.ch>
1 parent a68d167 commit a8b2641

File tree

5 files changed

+157
-4
lines changed

5 files changed

+157
-4
lines changed

src/client/play.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ module.exports = function (client, options) {
5656
client.once('select_known_packs', () => {
5757
client.write('select_known_packs', { packs: [] })
5858
})
59+
client.once('code_of_conduct', () => {
60+
client.write('accept_code_of_conduct', {})
61+
})
5962
// Server should send finish_configuration on its own right after sending the client a dimension codec
6063
// for login (that has data about world height, world gen, etc) after getting a login success from client
6164
client.once('finish_configuration', () => {

src/datatypes/compiler-minecraft.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ if (n !== 0) {
7070
return { value: { ${opts.otherwise.name}: set }, size: accSize }
7171
}
7272
`.trim())
73-
}]
73+
}],
74+
lpVec3: ['native', minecraft.lpVec3[0]]
7475
},
7576
Write: {
7677
varlong: ['native', minecraft.varlong[1]],
@@ -135,7 +136,8 @@ if (${baseName} != null) {
135136
}
136137
return offset
137138
`.trim())
138-
}]
139+
}],
140+
lpVec3: ['native', minecraft.lpVec3[1]]
139141
},
140142
SizeOf: {
141143
varlong: ['native', minecraft.varlong[2]],
@@ -194,6 +196,7 @@ if (${baseName} != null) {
194196
}
195197
return size
196198
`.trim())
197-
}]
199+
}],
200+
lpVec3: ['native', minecraft.lpVec3[2]]
198201
}
199202
}

src/datatypes/lpVec3.js

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
const [readVarInt, writeVarInt, sizeOfVarInt] = require('protodef').types.varint
2+
3+
// Adapted from https://github.com/extremeheat/extracted_minecraft_data/blob/client1.21.10/client/net/minecraft/network/LpVec3.java
4+
5+
const DATA_BITS_MASK = 32767
6+
const MAX_QUANTIZED_VALUE = 32766.0
7+
const SCALE_BITS = 2
8+
const SCALE_BITS_MASK = 3
9+
const CONTINUATION_FLAG = 4
10+
const X_OFFSET = 3
11+
const Y_OFFSET = 18
12+
const Z_OFFSET = 33
13+
const ABS_MAX_VALUE = 1.7179869183e10
14+
const ABS_MIN_VALUE = 3.051944088384301e-5
15+
16+
function hasContinuationBit (a) {
17+
return (a & CONTINUATION_FLAG) === CONTINUATION_FLAG
18+
}
19+
20+
function sanitize (value) {
21+
if (Number.isNaN(value)) return 0.0
22+
return Math.max(-ABS_MAX_VALUE, Math.min(value, ABS_MAX_VALUE))
23+
}
24+
25+
function pack (value) {
26+
return BigInt(Math.round((value * 0.5 + 0.5) * MAX_QUANTIZED_VALUE))
27+
}
28+
29+
function unpack (bits) {
30+
const masked = Number(bits & BigInt(DATA_BITS_MASK))
31+
const clamped = Math.min(masked, MAX_QUANTIZED_VALUE)
32+
return (clamped * 2.0) / MAX_QUANTIZED_VALUE - 1.0
33+
}
34+
35+
function readLpVec3 (buffer, offset) {
36+
if (offset + 1 > buffer.length) throw new Error('Unexpected end while reading LpVec3')
37+
const a = buffer.readUInt8(offset)
38+
39+
if (a === 0) {
40+
return { value: { x: 0, y: 0, z: 0 }, size: 1 }
41+
}
42+
43+
if (offset + 6 > buffer.length) throw new Error('Unexpected end while reading LpVec3')
44+
const b = buffer.readUInt8(offset + 1)
45+
const c = buffer.readUInt32LE(offset + 2)
46+
47+
const packed = (BigInt(c >>> 0) << 16n) | (BigInt(b & 0xff) << 8n) | BigInt(a & 0xff)
48+
49+
let scale = BigInt(a & SCALE_BITS_MASK)
50+
let totalSize = 6
51+
52+
if (hasContinuationBit(a)) {
53+
const dRes = readVarInt(buffer, offset + 6)
54+
scale |= (BigInt(dRes.value >>> 0) << BigInt(SCALE_BITS))
55+
totalSize = 6 + dRes.size
56+
}
57+
58+
const x = unpack(packed >> BigInt(X_OFFSET)) * Number(scale)
59+
const y = unpack(packed >> BigInt(Y_OFFSET)) * Number(scale)
60+
const z = unpack(packed >> BigInt(Z_OFFSET)) * Number(scale)
61+
62+
return { value: { x, y, z }, size: totalSize }
63+
}
64+
65+
function writeLpVec3 (value, buffer, offset) {
66+
const x = sanitize(value.x)
67+
const y = sanitize(value.y)
68+
const z = sanitize(value.z)
69+
70+
const max = Math.max(Math.abs(x), Math.abs(y), Math.abs(z))
71+
72+
if (max < ABS_MIN_VALUE) {
73+
buffer.writeUInt8(0, offset)
74+
return offset + 1
75+
}
76+
77+
const scale = BigInt(Math.ceil(max))
78+
const needsContinuation = (scale & BigInt(SCALE_BITS_MASK)) !== scale
79+
80+
const scaleByte = needsContinuation ? ((scale & BigInt(SCALE_BITS_MASK)) | BigInt(CONTINUATION_FLAG)) : scale
81+
const scaleNum = Number(scale)
82+
83+
const packedX = pack(x / scaleNum) << BigInt(X_OFFSET)
84+
const packedY = pack(y / scaleNum) << BigInt(Y_OFFSET)
85+
const packedZ = pack(z / scaleNum) << BigInt(Z_OFFSET)
86+
87+
const packed = scaleByte | packedX | packedY | packedZ
88+
89+
buffer.writeUInt8(Number(packed) & 0xff, offset)
90+
buffer.writeUInt8(Number((packed >> 8n) & 0xffn) & 0xff, offset + 1)
91+
buffer.writeUInt32LE(Number((packed >> 16n) & 0xffffffffn) >>> 0, offset + 2)
92+
93+
if (needsContinuation) {
94+
return writeVarInt(Number(scale >> BigInt(SCALE_BITS)) >>> 0, buffer, offset + 6)
95+
}
96+
return offset + 6
97+
}
98+
99+
function sizeOfLpVec3 (value) {
100+
const x = sanitize(value.x)
101+
const y = sanitize(value.y)
102+
const z = sanitize(value.z)
103+
104+
const max = Math.max(Math.abs(x), Math.abs(y), Math.abs(z))
105+
106+
if (max < ABS_MIN_VALUE) return 1
107+
108+
const scale = BigInt(Math.ceil(max))
109+
const needsContinuation = (scale & BigInt(SCALE_BITS_MASK)) !== scale
110+
111+
if (needsContinuation) {
112+
return 6 + sizeOfVarInt(Number(scale >> BigInt(SCALE_BITS)) >>> 0)
113+
}
114+
return 6
115+
}
116+
117+
module.exports = [readLpVec3, writeLpVec3, sizeOfLpVec3]

src/datatypes/minecraft.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,16 @@ const nbt = require('prismarine-nbt')
44
const UUID = require('uuid-1345')
55
const zlib = require('zlib')
66
const [readVarInt, writeVarInt, sizeOfVarInt] = require('protodef').types.varint
7+
const [readLpVec3, writeLpVec3, sizeOfLpVec3] = require('./lpVec3')
78

89
module.exports = {
910
varlong: [readVarLong, writeVarLong, sizeOfVarLong],
1011
UUID: [readUUID, writeUUID, 16],
1112
compressedNbt: [readCompressedNbt, writeCompressedNbt, sizeOfCompressedNbt],
1213
restBuffer: [readRestBuffer, writeRestBuffer, sizeOfRestBuffer],
1314
entityMetadataLoop: [readEntityMetadata, writeEntityMetadata, sizeOfEntityMetadata],
14-
topBitSetTerminatedArray: [readTopBitSetTerminatedArray, writeTopBitSetTerminatedArray, sizeOfTopBitSetTerminatedArray]
15+
topBitSetTerminatedArray: [readTopBitSetTerminatedArray, writeTopBitSetTerminatedArray, sizeOfTopBitSetTerminatedArray],
16+
lpVec3: [readLpVec3, writeLpVec3, sizeOfLpVec3]
1517
}
1618
const PartialReadError = require('protodef').utils.PartialReadError
1719

test/packetTest.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,34 @@ const values = {
415415
RecipeBookSetting: {
416416
open: false,
417417
filtering: false
418+
},
419+
lpVec3: { x: 0, y: 0, z: 0 },
420+
DebugSubscriptionDataType: 0,
421+
DebugSubscriptionUpdate: {
422+
type: 0
423+
},
424+
DebugSubscriptionEvent: {
425+
type: 0
426+
},
427+
RespawnData: {
428+
globalPos: {
429+
dimensionName: 'minecraft:overworld',
430+
location: { x: 0, y: 64, z: 0 }
431+
},
432+
yaw: 0,
433+
pitch: 0
434+
},
435+
GlobalPos: {
436+
dimensionName: 'minecraft:overworld',
437+
location: { x: 0, y: 64, z: 0 }
438+
},
439+
ExplosionParticleInfo: {
440+
particle: {
441+
particleId: 0,
442+
data: null
443+
},
444+
speed: 0,
445+
scaling: 0
418446
}
419447
}
420448

0 commit comments

Comments
 (0)