protocol-classicube 0.6.1
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/Binary.js +149 -0
- package/PacketIDs.js +35 -0
- package/client/ClientConnection.js +308 -0
- package/index.js +62 -0
- package/package.json +29 -0
- package/packets/ChatMessage.js +48 -0
- package/packets/DespawnPlayer.js +38 -0
- package/packets/Disconnect.js +36 -0
- package/packets/LevelDataChunk.js +47 -0
- package/packets/LevelFinalize.js +44 -0
- package/packets/LevelInitialize.js +29 -0
- package/packets/Ping.js +29 -0
- package/packets/PlayerIdentification.js +48 -0
- package/packets/PlayerMove.js +52 -0
- package/packets/PlayerRotate.js +46 -0
- package/packets/PlayerTeleport.js +59 -0
- package/packets/PlayerUpdate.js +62 -0
- package/packets/ServerIdentification.js +63 -0
- package/packets/SetBlock.js +93 -0
- package/packets/SpawnPlayer.js +62 -0
- package/packets/UpdateUserType.js +51 -0
- package/server/ServerConnection.js +249 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Packet 0x03 - Level Data Chunk (Server -> Client)
|
|
3
|
+
*
|
|
4
|
+
* Sends a chunk of gzipped level data.
|
|
5
|
+
* The level data itself is: Int (block count) + raw block IDs,
|
|
6
|
+
* all gzipped, then split into 1024-byte chunks.
|
|
7
|
+
*
|
|
8
|
+
* Layout:
|
|
9
|
+
* Byte - Packet ID (0x03)
|
|
10
|
+
* Short - Chunk length (number of meaningful bytes in this chunk, 0–1024)
|
|
11
|
+
* ByteArray - 1024 bytes of chunk data (padded with 0x00 if needed)
|
|
12
|
+
* Byte - Percent complete (0–100)
|
|
13
|
+
*
|
|
14
|
+
* Total: 1028 bytes
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const { BinaryWriter, BinaryReader } = require('../Binary');
|
|
18
|
+
const PacketIDs = require('../PacketIDs');
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @param {object} opts
|
|
22
|
+
* @param {Buffer} opts.chunkData - Raw chunk bytes (up to 1024)
|
|
23
|
+
* @param {number} opts.chunkLength - Actual meaningful bytes in chunkData
|
|
24
|
+
* @param {number} opts.percent - 0-100 completion percent
|
|
25
|
+
*/
|
|
26
|
+
function serialize({ chunkData, chunkLength, percent }) {
|
|
27
|
+
return new BinaryWriter()
|
|
28
|
+
.writeByte(PacketIDs.SERVER.LEVEL_DATA_CHUNK)
|
|
29
|
+
.writeShort(chunkLength)
|
|
30
|
+
.writeByteArray(chunkData)
|
|
31
|
+
.writeByte(percent)
|
|
32
|
+
.toBuffer();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function deserialize(buf) {
|
|
36
|
+
const r = new BinaryReader(buf);
|
|
37
|
+
const packetId = r.readByte();
|
|
38
|
+
if (packetId !== PacketIDs.SERVER.LEVEL_DATA_CHUNK) {
|
|
39
|
+
throw new Error(`Expected LevelDataChunk (0x03), got 0x${packetId.toString(16)}`);
|
|
40
|
+
}
|
|
41
|
+
const chunkLength = r.readShort();
|
|
42
|
+
const chunkData = r.readByteArray();
|
|
43
|
+
const percent = r.readByte();
|
|
44
|
+
return { packetId, chunkLength, chunkData, percent };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
module.exports = { serialize, deserialize, PACKET_SIZE: 1028 };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Packet 0x04 - Level Finalize (Server -> Client)
|
|
3
|
+
*
|
|
4
|
+
* Sent after all LevelDataChunk packets. Gives the world dimensions.
|
|
5
|
+
* Layout:
|
|
6
|
+
* Byte - Packet ID (0x04)
|
|
7
|
+
* Short - X size (width)
|
|
8
|
+
* Short - Y size (height)
|
|
9
|
+
* Short - Z size (depth)
|
|
10
|
+
*
|
|
11
|
+
* Total: 7 bytes
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const { BinaryWriter, BinaryReader } = require('../Binary');
|
|
15
|
+
const PacketIDs = require('../PacketIDs');
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @param {object} opts
|
|
19
|
+
* @param {number} opts.xSize
|
|
20
|
+
* @param {number} opts.ySize
|
|
21
|
+
* @param {number} opts.zSize
|
|
22
|
+
*/
|
|
23
|
+
function serialize({ xSize, ySize, zSize }) {
|
|
24
|
+
return new BinaryWriter()
|
|
25
|
+
.writeByte(PacketIDs.SERVER.LEVEL_FINALIZE)
|
|
26
|
+
.writeShort(xSize)
|
|
27
|
+
.writeShort(ySize)
|
|
28
|
+
.writeShort(zSize)
|
|
29
|
+
.toBuffer();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function deserialize(buf) {
|
|
33
|
+
const r = new BinaryReader(buf);
|
|
34
|
+
const packetId = r.readByte();
|
|
35
|
+
if (packetId !== PacketIDs.SERVER.LEVEL_FINALIZE) {
|
|
36
|
+
throw new Error(`Expected LevelFinalize (0x04), got 0x${packetId.toString(16)}`);
|
|
37
|
+
}
|
|
38
|
+
const xSize = r.readShort();
|
|
39
|
+
const ySize = r.readShort();
|
|
40
|
+
const zSize = r.readShort();
|
|
41
|
+
return { packetId, xSize, ySize, zSize };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
module.exports = { serialize, deserialize, PACKET_SIZE: 7 };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Packet 0x02 - Level Initialize (Server -> Client)
|
|
3
|
+
*
|
|
4
|
+
* Tells the client that level data is about to be sent.
|
|
5
|
+
* Layout:
|
|
6
|
+
* Byte - Packet ID (0x02)
|
|
7
|
+
*
|
|
8
|
+
* Total: 1 byte
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const { BinaryWriter, BinaryReader } = require('../Binary');
|
|
12
|
+
const PacketIDs = require('../PacketIDs');
|
|
13
|
+
|
|
14
|
+
function serialize() {
|
|
15
|
+
return new BinaryWriter()
|
|
16
|
+
.writeByte(PacketIDs.SERVER.LEVEL_INITIALIZE)
|
|
17
|
+
.toBuffer();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function deserialize(buf) {
|
|
21
|
+
const r = new BinaryReader(buf);
|
|
22
|
+
const packetId = r.readByte();
|
|
23
|
+
if (packetId !== PacketIDs.SERVER.LEVEL_INITIALIZE) {
|
|
24
|
+
throw new Error(`Expected LevelInitialize (0x02), got 0x${packetId.toString(16)}`);
|
|
25
|
+
}
|
|
26
|
+
return { packetId };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
module.exports = { serialize, deserialize, PACKET_SIZE: 1 };
|
package/packets/Ping.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Packet 0x01 - Ping (Server -> Client)
|
|
3
|
+
*
|
|
4
|
+
* A single-byte keep-alive packet. No payload.
|
|
5
|
+
* Layout:
|
|
6
|
+
* Byte - Packet ID (0x01)
|
|
7
|
+
*
|
|
8
|
+
* Total: 1 byte
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const { BinaryWriter, BinaryReader } = require('../Binary');
|
|
12
|
+
const PacketIDs = require('../PacketIDs');
|
|
13
|
+
|
|
14
|
+
function serialize() {
|
|
15
|
+
return new BinaryWriter()
|
|
16
|
+
.writeByte(PacketIDs.SERVER.PING)
|
|
17
|
+
.toBuffer();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function deserialize(buf) {
|
|
21
|
+
const r = new BinaryReader(buf);
|
|
22
|
+
const packetId = r.readByte();
|
|
23
|
+
if (packetId !== PacketIDs.SERVER.PING) {
|
|
24
|
+
throw new Error(`Expected Ping (0x01), got 0x${packetId.toString(16)}`);
|
|
25
|
+
}
|
|
26
|
+
return { packetId };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
module.exports = { serialize, deserialize, PACKET_SIZE: 1 };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Packet 0x00 - Player Identification (Client -> Server)
|
|
3
|
+
*
|
|
4
|
+
* Primer paquete que envia el cliente al conectar.
|
|
5
|
+
* Layout:
|
|
6
|
+
* Byte - Packet ID (0x00)
|
|
7
|
+
* Byte - Protocol version (siempre 7)
|
|
8
|
+
* String - Username (64 bytes)
|
|
9
|
+
* String - Verification key (64 bytes, '-' si no hay auth)
|
|
10
|
+
* Byte - Unused (siempre 0x00)
|
|
11
|
+
*
|
|
12
|
+
* Total: 131 bytes
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const { BinaryWriter, BinaryReader } = require('../Binary');
|
|
16
|
+
const PacketIDs = require('../PacketIDs');
|
|
17
|
+
|
|
18
|
+
const PROTOCOL_VERSION = 7;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @param {object} opts
|
|
22
|
+
* @param {string} opts.username
|
|
23
|
+
* @param {string} [opts.verificationKey]
|
|
24
|
+
*/
|
|
25
|
+
function serialize({ username, verificationKey = '-' }) {
|
|
26
|
+
return new BinaryWriter()
|
|
27
|
+
.writeByte(PacketIDs.CLIENT.PLAYER_IDENTIFICATION)
|
|
28
|
+
.writeByte(PROTOCOL_VERSION)
|
|
29
|
+
.writeString(username)
|
|
30
|
+
.writeString(verificationKey)
|
|
31
|
+
.writeByte(0x00)
|
|
32
|
+
.toBuffer();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function deserialize(buf) {
|
|
36
|
+
const r = new BinaryReader(buf);
|
|
37
|
+
const packetId = r.readByte();
|
|
38
|
+
if (packetId !== PacketIDs.CLIENT.PLAYER_IDENTIFICATION) {
|
|
39
|
+
throw new Error(`Expected PlayerIdentification (0x00), got 0x${packetId.toString(16)}`);
|
|
40
|
+
}
|
|
41
|
+
const protocolVersion = r.readByte();
|
|
42
|
+
const username = r.readString();
|
|
43
|
+
const verificationKey = r.readString();
|
|
44
|
+
r.readByte(); // unused
|
|
45
|
+
return { packetId, protocolVersion, username, verificationKey };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
module.exports = { serialize, deserialize, PACKET_SIZE: 131, PROTOCOL_VERSION };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Packet 0x0A - Player Move (Server -> Client)
|
|
3
|
+
*
|
|
4
|
+
* Movimiento relativo (delta) de posicion SIN cambio de orientacion.
|
|
5
|
+
* Mas eficiente que PlayerUpdate cuando el jugador no gira.
|
|
6
|
+
*
|
|
7
|
+
* Los deltas son SByte en fixed-point: valor / 32
|
|
8
|
+
*
|
|
9
|
+
* Layout:
|
|
10
|
+
* Byte - Packet ID (0x0A)
|
|
11
|
+
* SByte - Player ID
|
|
12
|
+
* SByte - Delta X (fixed-point * 32)
|
|
13
|
+
* SByte - Delta Y (fixed-point * 32)
|
|
14
|
+
* SByte - Delta Z (fixed-point * 32)
|
|
15
|
+
*
|
|
16
|
+
* Total: 5 bytes
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
const { BinaryWriter, BinaryReader } = require('../Binary');
|
|
20
|
+
const PacketIDs = require('../PacketIDs');
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @param {object} opts
|
|
24
|
+
* @param {number} opts.playerId
|
|
25
|
+
* @param {number} opts.dx
|
|
26
|
+
* @param {number} opts.dy
|
|
27
|
+
* @param {number} opts.dz
|
|
28
|
+
*/
|
|
29
|
+
function serialize({ playerId, dx, dy, dz }) {
|
|
30
|
+
return new BinaryWriter()
|
|
31
|
+
.writeByte(PacketIDs.SERVER.PLAYER_MOVE)
|
|
32
|
+
.writeSByte(playerId)
|
|
33
|
+
.writeSByte(Math.round(dx * 32))
|
|
34
|
+
.writeSByte(Math.round(dy * 32))
|
|
35
|
+
.writeSByte(Math.round(dz * 32))
|
|
36
|
+
.toBuffer();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function deserialize(buf) {
|
|
40
|
+
const r = new BinaryReader(buf);
|
|
41
|
+
const packetId = r.readByte();
|
|
42
|
+
if (packetId !== PacketIDs.SERVER.PLAYER_MOVE) {
|
|
43
|
+
throw new Error(`Expected PlayerMove (0x0A), got 0x${packetId.toString(16)}`);
|
|
44
|
+
}
|
|
45
|
+
const playerId = r.readSByte();
|
|
46
|
+
const dx = r.readSByte() / 32;
|
|
47
|
+
const dy = r.readSByte() / 32;
|
|
48
|
+
const dz = r.readSByte() / 32;
|
|
49
|
+
return { packetId, playerId, dx, dy, dz };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
module.exports = { serialize, deserialize, PACKET_SIZE: 5 };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Packet 0x0B - Player Rotate (Server -> Client)
|
|
3
|
+
*
|
|
4
|
+
* Cambio de orientacion SIN movimiento de posicion.
|
|
5
|
+
* Mas eficiente que PlayerUpdate cuando el jugador solo gira en sitio.
|
|
6
|
+
*
|
|
7
|
+
* Layout:
|
|
8
|
+
* Byte - Packet ID (0x0B)
|
|
9
|
+
* SByte - Player ID
|
|
10
|
+
* Byte - Yaw (0-255 = 0-360 grados)
|
|
11
|
+
* Byte - Pitch (0-255 = 0-360 grados)
|
|
12
|
+
*
|
|
13
|
+
* Total: 4 bytes
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const { BinaryWriter, BinaryReader } = require('../Binary');
|
|
17
|
+
const PacketIDs = require('../PacketIDs');
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @param {object} opts
|
|
21
|
+
* @param {number} opts.playerId
|
|
22
|
+
* @param {number} opts.yaw - 0-255
|
|
23
|
+
* @param {number} opts.pitch - 0-255
|
|
24
|
+
*/
|
|
25
|
+
function serialize({ playerId, yaw, pitch }) {
|
|
26
|
+
return new BinaryWriter()
|
|
27
|
+
.writeByte(PacketIDs.SERVER.PLAYER_ROTATE)
|
|
28
|
+
.writeSByte(playerId)
|
|
29
|
+
.writeByte(yaw & 0xFF)
|
|
30
|
+
.writeByte(pitch & 0xFF)
|
|
31
|
+
.toBuffer();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function deserialize(buf) {
|
|
35
|
+
const r = new BinaryReader(buf);
|
|
36
|
+
const packetId = r.readByte();
|
|
37
|
+
if (packetId !== PacketIDs.SERVER.PLAYER_ROTATE) {
|
|
38
|
+
throw new Error(`Expected PlayerRotate (0x0B), got 0x${packetId.toString(16)}`);
|
|
39
|
+
}
|
|
40
|
+
const playerId = r.readSByte();
|
|
41
|
+
const yaw = r.readByte();
|
|
42
|
+
const pitch = r.readByte();
|
|
43
|
+
return { packetId, playerId, yaw, pitch };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
module.exports = { serialize, deserialize, PACKET_SIZE: 4 };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Packet 0x08 - Player Teleport (Server -> Client / Client -> Server)
|
|
3
|
+
*
|
|
4
|
+
* Teleports a player to an absolute position.
|
|
5
|
+
* When sent by the client, Player ID is always 255 (0xFF = self).
|
|
6
|
+
* When sent by the server, Player ID identifies which player to move.
|
|
7
|
+
*
|
|
8
|
+
* Layout:
|
|
9
|
+
* Byte - Packet ID (0x08)
|
|
10
|
+
* SByte - Player ID
|
|
11
|
+
* Short - X (fixed-point * 32)
|
|
12
|
+
* Short - Y (fixed-point * 32)
|
|
13
|
+
* Short - Z (fixed-point * 32)
|
|
14
|
+
* Byte - Yaw
|
|
15
|
+
* Byte - Pitch
|
|
16
|
+
*
|
|
17
|
+
* Total: 10 bytes
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const { BinaryWriter, BinaryReader } = require('../Binary');
|
|
21
|
+
const PacketIDs = require('../PacketIDs');
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @param {object} opts
|
|
25
|
+
* @param {number} opts.playerId
|
|
26
|
+
* @param {number} opts.x
|
|
27
|
+
* @param {number} opts.y
|
|
28
|
+
* @param {number} opts.z
|
|
29
|
+
* @param {number} opts.yaw
|
|
30
|
+
* @param {number} opts.pitch
|
|
31
|
+
*/
|
|
32
|
+
function serialize({ playerId, x, y, z, yaw, pitch }) {
|
|
33
|
+
return new BinaryWriter()
|
|
34
|
+
.writeByte(PacketIDs.SERVER.PLAYER_TELEPORT)
|
|
35
|
+
.writeSByte(playerId)
|
|
36
|
+
.writeShort(Math.round(x * 32))
|
|
37
|
+
.writeShort(Math.round(y * 32))
|
|
38
|
+
.writeShort(Math.round(z * 32))
|
|
39
|
+
.writeByte(yaw & 0xFF)
|
|
40
|
+
.writeByte(pitch & 0xFF)
|
|
41
|
+
.toBuffer();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function deserialize(buf) {
|
|
45
|
+
const r = new BinaryReader(buf);
|
|
46
|
+
const packetId = r.readByte();
|
|
47
|
+
if (packetId !== PacketIDs.SERVER.PLAYER_TELEPORT) {
|
|
48
|
+
throw new Error(`Expected PlayerTeleport (0x08), got 0x${packetId.toString(16)}`);
|
|
49
|
+
}
|
|
50
|
+
const playerId = r.readSByte();
|
|
51
|
+
const x = r.readShort() / 32;
|
|
52
|
+
const y = r.readShort() / 32;
|
|
53
|
+
const z = r.readShort() / 32;
|
|
54
|
+
const yaw = r.readByte();
|
|
55
|
+
const pitch = r.readByte();
|
|
56
|
+
return { packetId, playerId, x, y, z, yaw, pitch };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
module.exports = { serialize, deserialize, PACKET_SIZE: 10 };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Packet 0x09 - Player Update (Server -> Client)
|
|
3
|
+
*
|
|
4
|
+
* Movimiento relativo (delta) de posicion + cambio de orientacion.
|
|
5
|
+
* Se usa para actualizaciones pequenas de posicion (< 4 bloques).
|
|
6
|
+
* Para movimientos grandes usar PlayerTeleport (0x08).
|
|
7
|
+
*
|
|
8
|
+
* Los deltas son SByte en fixed-point: valor / 32
|
|
9
|
+
* Rango util: -4 a +3.96875 bloques por eje.
|
|
10
|
+
*
|
|
11
|
+
* Layout:
|
|
12
|
+
* Byte - Packet ID (0x09)
|
|
13
|
+
* SByte - Player ID
|
|
14
|
+
* SByte - Delta X (fixed-point * 32)
|
|
15
|
+
* SByte - Delta Y (fixed-point * 32)
|
|
16
|
+
* SByte - Delta Z (fixed-point * 32)
|
|
17
|
+
* Byte - Yaw (0-255)
|
|
18
|
+
* Byte - Pitch (0-255)
|
|
19
|
+
*
|
|
20
|
+
* Total: 7 bytes
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
const { BinaryWriter, BinaryReader } = require('../Binary');
|
|
24
|
+
const PacketIDs = require('../PacketIDs');
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @param {object} opts
|
|
28
|
+
* @param {number} opts.playerId
|
|
29
|
+
* @param {number} opts.dx - Delta X en bloques (se multiplica * 32)
|
|
30
|
+
* @param {number} opts.dy - Delta Y en bloques
|
|
31
|
+
* @param {number} opts.dz - Delta Z en bloques
|
|
32
|
+
* @param {number} opts.yaw - 0-255
|
|
33
|
+
* @param {number} opts.pitch - 0-255
|
|
34
|
+
*/
|
|
35
|
+
function serialize({ playerId, dx, dy, dz, yaw, pitch }) {
|
|
36
|
+
return new BinaryWriter()
|
|
37
|
+
.writeByte(PacketIDs.SERVER.PLAYER_UPDATE)
|
|
38
|
+
.writeSByte(playerId)
|
|
39
|
+
.writeSByte(Math.round(dx * 32))
|
|
40
|
+
.writeSByte(Math.round(dy * 32))
|
|
41
|
+
.writeSByte(Math.round(dz * 32))
|
|
42
|
+
.writeByte(yaw & 0xFF)
|
|
43
|
+
.writeByte(pitch & 0xFF)
|
|
44
|
+
.toBuffer();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function deserialize(buf) {
|
|
48
|
+
const r = new BinaryReader(buf);
|
|
49
|
+
const packetId = r.readByte();
|
|
50
|
+
if (packetId !== PacketIDs.SERVER.PLAYER_UPDATE) {
|
|
51
|
+
throw new Error(`Expected PlayerUpdate (0x09), got 0x${packetId.toString(16)}`);
|
|
52
|
+
}
|
|
53
|
+
const playerId = r.readSByte();
|
|
54
|
+
const dx = r.readSByte() / 32;
|
|
55
|
+
const dy = r.readSByte() / 32;
|
|
56
|
+
const dz = r.readSByte() / 32;
|
|
57
|
+
const yaw = r.readByte();
|
|
58
|
+
const pitch = r.readByte();
|
|
59
|
+
return { packetId, playerId, dx, dy, dz, yaw, pitch };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
module.exports = { serialize, deserialize, PACKET_SIZE: 7 };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Packet 0x00 - Server Identification (Server -> Client)
|
|
3
|
+
*
|
|
4
|
+
* Sent immediately after client connects.
|
|
5
|
+
* Layout:
|
|
6
|
+
* Byte - Packet ID (0x00)
|
|
7
|
+
* Byte - Protocol version (always 7)
|
|
8
|
+
* String - Server name (64 bytes)
|
|
9
|
+
* String - Server MOTD (64 bytes)
|
|
10
|
+
* Byte - User type (0x00 = normal, 0x64 = op)
|
|
11
|
+
*
|
|
12
|
+
* Total: 131 bytes
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const { BinaryWriter, BinaryReader } = require('../Binary');
|
|
16
|
+
const PacketIDs = require('../PacketIDs');
|
|
17
|
+
|
|
18
|
+
const PROTOCOL_VERSION = 7;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Serialize a ServerIdentification packet into a Buffer.
|
|
22
|
+
* @param {object} opts
|
|
23
|
+
* @param {string} opts.name - Server name
|
|
24
|
+
* @param {string} opts.motd - Server MOTD
|
|
25
|
+
* @param {boolean} [opts.op] - Is the connecting player an operator?
|
|
26
|
+
* @returns {Buffer}
|
|
27
|
+
*/
|
|
28
|
+
function serialize({ name, motd, op = false }) {
|
|
29
|
+
return new BinaryWriter()
|
|
30
|
+
.writeByte(PacketIDs.SERVER.SERVER_IDENTIFICATION)
|
|
31
|
+
.writeByte(PROTOCOL_VERSION)
|
|
32
|
+
.writeString(name)
|
|
33
|
+
.writeString(motd)
|
|
34
|
+
.writeByte(op ? 0x64 : 0x00)
|
|
35
|
+
.toBuffer();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Deserialize a ServerIdentification packet from a Buffer.
|
|
40
|
+
* Expects the packet ID byte to already be consumed or present at offset 0.
|
|
41
|
+
* @param {Buffer} buf
|
|
42
|
+
* @returns {{ protocolVersion: number, name: string, motd: string, op: boolean }}
|
|
43
|
+
*/
|
|
44
|
+
function deserialize(buf) {
|
|
45
|
+
const r = new BinaryReader(buf);
|
|
46
|
+
const packetId = r.readByte(); // 0x00
|
|
47
|
+
if (packetId !== PacketIDs.SERVER.SERVER_IDENTIFICATION) {
|
|
48
|
+
throw new Error(`Expected ServerIdentification (0x00), got 0x${packetId.toString(16)}`);
|
|
49
|
+
}
|
|
50
|
+
const protocolVersion = r.readByte();
|
|
51
|
+
const name = r.readString();
|
|
52
|
+
const motd = r.readString();
|
|
53
|
+
const userTypeByte = r.readByte();
|
|
54
|
+
return {
|
|
55
|
+
packetId,
|
|
56
|
+
protocolVersion,
|
|
57
|
+
name,
|
|
58
|
+
motd,
|
|
59
|
+
op: userTypeByte === 0x64,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
module.exports = { serialize, deserialize, PACKET_SIZE: 131 };
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SetBlock packets
|
|
3
|
+
*
|
|
4
|
+
* There are TWO different SetBlock packets:
|
|
5
|
+
*
|
|
6
|
+
* --- SERVER -> CLIENT (0x06) ---
|
|
7
|
+
* Tells the client a block changed.
|
|
8
|
+
* Byte - Packet ID (0x06)
|
|
9
|
+
* Short - X
|
|
10
|
+
* Short - Y
|
|
11
|
+
* Short - Z
|
|
12
|
+
* Byte - Block type
|
|
13
|
+
* Total: 8 bytes
|
|
14
|
+
*
|
|
15
|
+
* --- CLIENT -> SERVER (0x05) ---
|
|
16
|
+
* Client requests placing/destroying a block.
|
|
17
|
+
* Byte - Packet ID (0x05)
|
|
18
|
+
* Short - X
|
|
19
|
+
* Short - Y
|
|
20
|
+
* Short - Z
|
|
21
|
+
* Byte - Mode (0x00 = destroy, 0x01 = create)
|
|
22
|
+
* Byte - Block type
|
|
23
|
+
* Total: 9 bytes
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
const { BinaryWriter, BinaryReader } = require('../Binary');
|
|
27
|
+
const PacketIDs = require('../PacketIDs');
|
|
28
|
+
|
|
29
|
+
// Block placement modes
|
|
30
|
+
const Mode = {
|
|
31
|
+
DESTROY: 0x00,
|
|
32
|
+
CREATE: 0x01,
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Server->Client: notify block change
|
|
37
|
+
*/
|
|
38
|
+
function serializeServer({ x, y, z, blockType }) {
|
|
39
|
+
return new BinaryWriter()
|
|
40
|
+
.writeByte(PacketIDs.SERVER.SET_BLOCK)
|
|
41
|
+
.writeShort(x)
|
|
42
|
+
.writeShort(y)
|
|
43
|
+
.writeShort(z)
|
|
44
|
+
.writeByte(blockType)
|
|
45
|
+
.toBuffer();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function deserializeServer(buf) {
|
|
49
|
+
const r = new BinaryReader(buf);
|
|
50
|
+
const packetId = r.readByte();
|
|
51
|
+
if (packetId !== PacketIDs.SERVER.SET_BLOCK) {
|
|
52
|
+
throw new Error(`Expected SetBlock server (0x06), got 0x${packetId.toString(16)}`);
|
|
53
|
+
}
|
|
54
|
+
const x = r.readShort();
|
|
55
|
+
const y = r.readShort();
|
|
56
|
+
const z = r.readShort();
|
|
57
|
+
const blockType = r.readByte();
|
|
58
|
+
return { packetId, x, y, z, blockType };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Client->Server: request block change
|
|
63
|
+
*/
|
|
64
|
+
function serializeClient({ x, y, z, mode, blockType }) {
|
|
65
|
+
return new BinaryWriter()
|
|
66
|
+
.writeByte(PacketIDs.CLIENT.SET_BLOCK)
|
|
67
|
+
.writeShort(x)
|
|
68
|
+
.writeShort(y)
|
|
69
|
+
.writeShort(z)
|
|
70
|
+
.writeByte(mode)
|
|
71
|
+
.writeByte(blockType)
|
|
72
|
+
.toBuffer();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function deserializeClient(buf) {
|
|
76
|
+
const r = new BinaryReader(buf);
|
|
77
|
+
const packetId = r.readByte();
|
|
78
|
+
if (packetId !== PacketIDs.CLIENT.SET_BLOCK) {
|
|
79
|
+
throw new Error(`Expected SetBlock client (0x05), got 0x${packetId.toString(16)}`);
|
|
80
|
+
}
|
|
81
|
+
const x = r.readShort();
|
|
82
|
+
const y = r.readShort();
|
|
83
|
+
const z = r.readShort();
|
|
84
|
+
const mode = r.readByte();
|
|
85
|
+
const blockType = r.readByte();
|
|
86
|
+
return { packetId, x, y, z, mode, blockType };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
module.exports = {
|
|
90
|
+
Mode,
|
|
91
|
+
server: { serialize: serializeServer, deserialize: deserializeServer, PACKET_SIZE: 8 },
|
|
92
|
+
client: { serialize: serializeClient, deserialize: deserializeClient, PACKET_SIZE: 9 },
|
|
93
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Packet 0x07 - Spawn Player (Server -> Client)
|
|
3
|
+
*
|
|
4
|
+
* Spawns a player entity in the world.
|
|
5
|
+
* Player ID -1 (0xFF) = the local player.
|
|
6
|
+
*
|
|
7
|
+
* Layout:
|
|
8
|
+
* Byte - Packet ID (0x07)
|
|
9
|
+
* SByte - Player ID (-1 for self)
|
|
10
|
+
* String - Player name (64 bytes)
|
|
11
|
+
* Short - X (fixed-point: value / 32)
|
|
12
|
+
* Short - Y (fixed-point: value / 32)
|
|
13
|
+
* Short - Z (fixed-point: value / 32)
|
|
14
|
+
* Byte - Yaw (0-255 maps to 0-360°)
|
|
15
|
+
* Byte - Pitch (0-255 maps to 0-360°)
|
|
16
|
+
*
|
|
17
|
+
* Total: 74 bytes
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const { BinaryWriter, BinaryReader } = require('../Binary');
|
|
21
|
+
const PacketIDs = require('../PacketIDs');
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @param {object} opts
|
|
25
|
+
* @param {number} opts.playerId - -1 for self, 0-127 for others
|
|
26
|
+
* @param {string} opts.name - Player name
|
|
27
|
+
* @param {number} opts.x - Block-space X (will be multiplied by 32)
|
|
28
|
+
* @param {number} opts.y - Block-space Y
|
|
29
|
+
* @param {number} opts.z - Block-space Z
|
|
30
|
+
* @param {number} opts.yaw - 0-255
|
|
31
|
+
* @param {number} opts.pitch - 0-255
|
|
32
|
+
*/
|
|
33
|
+
function serialize({ playerId, name, x, y, z, yaw, pitch }) {
|
|
34
|
+
return new BinaryWriter()
|
|
35
|
+
.writeByte(PacketIDs.SERVER.SPAWN_PLAYER)
|
|
36
|
+
.writeSByte(playerId)
|
|
37
|
+
.writeString(name)
|
|
38
|
+
.writeShort(Math.round(x * 32))
|
|
39
|
+
.writeShort(Math.round(y * 32))
|
|
40
|
+
.writeShort(Math.round(z * 32))
|
|
41
|
+
.writeByte(yaw & 0xFF)
|
|
42
|
+
.writeByte(pitch & 0xFF)
|
|
43
|
+
.toBuffer();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function deserialize(buf) {
|
|
47
|
+
const r = new BinaryReader(buf);
|
|
48
|
+
const packetId = r.readByte();
|
|
49
|
+
if (packetId !== PacketIDs.SERVER.SPAWN_PLAYER) {
|
|
50
|
+
throw new Error(`Expected SpawnPlayer (0x07), got 0x${packetId.toString(16)}`);
|
|
51
|
+
}
|
|
52
|
+
const playerId = r.readSByte();
|
|
53
|
+
const name = r.readString();
|
|
54
|
+
const x = r.readShort() / 32;
|
|
55
|
+
const y = r.readShort() / 32;
|
|
56
|
+
const z = r.readShort() / 32;
|
|
57
|
+
const yaw = r.readByte();
|
|
58
|
+
const pitch = r.readByte();
|
|
59
|
+
return { packetId, playerId, name, x, y, z, yaw, pitch };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
module.exports = { serialize, deserialize, PACKET_SIZE: 74 };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Packet 0x0F - Update User Type (Server -> Client)
|
|
3
|
+
*
|
|
4
|
+
* Actualiza los permisos del jugador en tiempo real.
|
|
5
|
+
* Usado para dar/quitar rango de operador sin reconectar.
|
|
6
|
+
*
|
|
7
|
+
* User type values:
|
|
8
|
+
* 0x00 = jugador normal
|
|
9
|
+
* 0x64 = operador (puede borrar bloques de bedrock, etc.)
|
|
10
|
+
*
|
|
11
|
+
* Layout:
|
|
12
|
+
* Byte - Packet ID (0x0F)
|
|
13
|
+
* Byte - User type (0x00 normal | 0x64 op)
|
|
14
|
+
*
|
|
15
|
+
* Total: 2 bytes
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const { BinaryWriter, BinaryReader } = require('../Binary');
|
|
19
|
+
const PacketIDs = require('../PacketIDs');
|
|
20
|
+
|
|
21
|
+
const UserType = {
|
|
22
|
+
NORMAL: 0x00,
|
|
23
|
+
OPERATOR: 0x64,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @param {object} opts
|
|
28
|
+
* @param {boolean} opts.op - true = operador, false = normal
|
|
29
|
+
*/
|
|
30
|
+
function serialize({ op }) {
|
|
31
|
+
return new BinaryWriter()
|
|
32
|
+
.writeByte(PacketIDs.SERVER.UPDATE_USER_TYPE)
|
|
33
|
+
.writeByte(op ? UserType.OPERATOR : UserType.NORMAL)
|
|
34
|
+
.toBuffer();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function deserialize(buf) {
|
|
38
|
+
const r = new BinaryReader(buf);
|
|
39
|
+
const packetId = r.readByte();
|
|
40
|
+
if (packetId !== PacketIDs.SERVER.UPDATE_USER_TYPE) {
|
|
41
|
+
throw new Error(`Expected UpdateUserType (0x0F), got 0x${packetId.toString(16)}`);
|
|
42
|
+
}
|
|
43
|
+
const userType = r.readByte();
|
|
44
|
+
return {
|
|
45
|
+
packetId,
|
|
46
|
+
userType,
|
|
47
|
+
op: userType === UserType.OPERATOR,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
module.exports = { serialize, deserialize, PACKET_SIZE: 2, UserType };
|