packet-events-js 1.0.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.
Files changed (40) hide show
  1. package/README.md +398 -0
  2. package/package.json +31 -0
  3. package/src/auth/AuthHandler.js +138 -0
  4. package/src/auth/MojangAPI.js +186 -0
  5. package/src/client/MinecraftClient.js +336 -0
  6. package/src/crypto/Encryption.js +125 -0
  7. package/src/events/EventEmitter.js +267 -0
  8. package/src/events/PacketEvent.js +78 -0
  9. package/src/index.js +18 -0
  10. package/src/manager/PacketManager.js +258 -0
  11. package/src/protocol/ConnectionState.js +37 -0
  12. package/src/protocol/PacketDirection.js +8 -0
  13. package/src/protocol/ProtocolVersion.js +141 -0
  14. package/src/protocol/packets/Packet.js +119 -0
  15. package/src/protocol/packets/PacketRegistry.js +145 -0
  16. package/src/protocol/packets/handshake/HandshakePacket.js +44 -0
  17. package/src/protocol/packets/index.js +265 -0
  18. package/src/protocol/packets/login/DisconnectPacket.js +71 -0
  19. package/src/protocol/packets/login/EncryptionRequestPacket.js +47 -0
  20. package/src/protocol/packets/login/EncryptionResponsePacket.js +34 -0
  21. package/src/protocol/packets/login/LoginStartPacket.js +35 -0
  22. package/src/protocol/packets/login/LoginSuccessPacket.js +61 -0
  23. package/src/protocol/packets/login/SetCompressionPacket.js +29 -0
  24. package/src/protocol/packets/play/ChatPacket.js +238 -0
  25. package/src/protocol/packets/play/ChunkPacket.js +122 -0
  26. package/src/protocol/packets/play/EntityPacket.js +302 -0
  27. package/src/protocol/packets/play/KeepAlivePacket.js +55 -0
  28. package/src/protocol/packets/play/PlayerPositionPacket.js +266 -0
  29. package/src/protocol/packets/status/PingPacket.js +29 -0
  30. package/src/protocol/packets/status/PongPacket.js +29 -0
  31. package/src/protocol/packets/status/StatusRequestPacket.js +20 -0
  32. package/src/protocol/packets/status/StatusResponsePacket.js +58 -0
  33. package/src/protocol/types/NBT.js +594 -0
  34. package/src/protocol/types/Position.js +125 -0
  35. package/src/protocol/types/TextComponent.js +355 -0
  36. package/src/protocol/types/UUID.js +105 -0
  37. package/src/protocol/types/VarInt.js +144 -0
  38. package/src/protocol/types/index.js +5 -0
  39. package/src/utils/Logger.js +207 -0
  40. package/src/utils/PacketBuffer.js +389 -0
@@ -0,0 +1,355 @@
1
+ export const ChatColor = Object.freeze({
2
+ BLACK: 'black',
3
+ DARK_BLUE: 'dark_blue',
4
+ DARK_GREEN: 'dark_green',
5
+ DARK_AQUA: 'dark_aqua',
6
+ DARK_RED: 'dark_red',
7
+ DARK_PURPLE: 'dark_purple',
8
+ GOLD: 'gold',
9
+ GRAY: 'gray',
10
+ DARK_GRAY: 'dark_gray',
11
+ BLUE: 'blue',
12
+ GREEN: 'green',
13
+ AQUA: 'aqua',
14
+ RED: 'red',
15
+ LIGHT_PURPLE: 'light_purple',
16
+ YELLOW: 'yellow',
17
+ WHITE: 'white',
18
+
19
+ hex: (hex) => hex.startsWith('#') ? hex : `#${hex}`
20
+ });
21
+
22
+ export const ChatFormat = Object.freeze({
23
+ BOLD: 'bold',
24
+ ITALIC: 'italic',
25
+ UNDERLINED: 'underlined',
26
+ STRIKETHROUGH: 'strikethrough',
27
+ OBFUSCATED: 'obfuscated'
28
+ });
29
+
30
+ export const ClickAction = Object.freeze({
31
+ OPEN_URL: 'open_url',
32
+ RUN_COMMAND: 'run_command',
33
+ SUGGEST_COMMAND: 'suggest_command',
34
+ CHANGE_PAGE: 'change_page',
35
+ COPY_TO_CLIPBOARD: 'copy_to_clipboard'
36
+ });
37
+
38
+ export const HoverAction = Object.freeze({
39
+ SHOW_TEXT: 'show_text',
40
+ SHOW_ITEM: 'show_item',
41
+ SHOW_ENTITY: 'show_entity'
42
+ });
43
+
44
+ export class TextComponent {
45
+ constructor(text = '') {
46
+ this._data = {};
47
+
48
+ if (text) {
49
+ this._data.text = text;
50
+ }
51
+ }
52
+
53
+ static text(text) {
54
+ return new TextComponent(text);
55
+ }
56
+
57
+ static translatable(key, ...args) {
58
+ const component = new TextComponent();
59
+ component._data.translate = key;
60
+
61
+ if (args.length > 0) {
62
+ component._data.with = args.map(arg =>
63
+ arg instanceof TextComponent ? arg.toJSON() : { text: String(arg) }
64
+ );
65
+ }
66
+
67
+ return component;
68
+ }
69
+
70
+ static keybind(keybind) {
71
+ const component = new TextComponent();
72
+ component._data.keybind = keybind;
73
+ return component;
74
+ }
75
+
76
+ static score(name, objective, value) {
77
+ const component = new TextComponent();
78
+ component._data.score = { name, objective };
79
+
80
+ if (value !== undefined) {
81
+ component._data.score.value = value;
82
+ }
83
+
84
+ return component;
85
+ }
86
+
87
+ static selector(selector, separator) {
88
+ const component = new TextComponent();
89
+ component._data.selector = selector;
90
+
91
+ if (separator) {
92
+ component._data.separator = separator.toJSON();
93
+ }
94
+
95
+ return component;
96
+ }
97
+
98
+ static nbt(nbt, interpret = false, separator) {
99
+ const component = new TextComponent();
100
+ component._data.nbt = nbt;
101
+ component._data.interpret = interpret;
102
+
103
+ if (separator) {
104
+ component._data.separator = separator.toJSON();
105
+ }
106
+
107
+ return component;
108
+ }
109
+
110
+ block(coords) {
111
+ this._data.block = coords;
112
+ return this;
113
+ }
114
+
115
+ entity(selector) {
116
+ this._data.entity = selector;
117
+ return this;
118
+ }
119
+
120
+ storage(storage) {
121
+ this._data.storage = storage;
122
+ return this;
123
+ }
124
+
125
+ color(color) {
126
+ this._data.color = color;
127
+ return this;
128
+ }
129
+
130
+ bold(value = true) {
131
+ this._data.bold = value;
132
+ return this;
133
+ }
134
+
135
+ italic(value = true) {
136
+ this._data.italic = value;
137
+ return this;
138
+ }
139
+
140
+ underlined(value = true) {
141
+ this._data.underlined = value;
142
+ return this;
143
+ }
144
+
145
+ strikethrough(value = true) {
146
+ this._data.strikethrough = value;
147
+ return this;
148
+ }
149
+
150
+ obfuscated(value = true) {
151
+ this._data.obfuscated = value;
152
+ return this;
153
+ }
154
+
155
+ font(font) {
156
+ this._data.font = font;
157
+ return this;
158
+ }
159
+
160
+ insertion(insertion) {
161
+ this._data.insertion = insertion;
162
+ return this;
163
+ }
164
+
165
+ clickEvent(action, value) {
166
+ this._data.clickEvent = { action, value };
167
+ return this;
168
+ }
169
+
170
+ openUrl(url) {
171
+ return this.clickEvent(ClickAction.OPEN_URL, url);
172
+ }
173
+
174
+ runCommand(command) {
175
+ return this.clickEvent(ClickAction.RUN_COMMAND, command);
176
+ }
177
+
178
+ suggestCommand(command) {
179
+ return this.clickEvent(ClickAction.SUGGEST_COMMAND, command);
180
+ }
181
+
182
+ copyToClipboard(text) {
183
+ return this.clickEvent(ClickAction.COPY_TO_CLIPBOARD, text);
184
+ }
185
+
186
+ hoverEvent(action, contents) {
187
+ this._data.hoverEvent = { action, contents };
188
+ return this;
189
+ }
190
+
191
+ showText(text) {
192
+ const contents = text instanceof TextComponent ? text.toJSON() : { text: String(text) };
193
+ return this.hoverEvent(HoverAction.SHOW_TEXT, contents);
194
+ }
195
+
196
+ showItem(id, count = 1, tag) {
197
+ const contents = { id, count };
198
+ if (tag) contents.tag = tag;
199
+ return this.hoverEvent(HoverAction.SHOW_ITEM, contents);
200
+ }
201
+
202
+ showEntity(type, id, name) {
203
+ const contents = { type, id };
204
+ if (name) {
205
+ contents.name = name instanceof TextComponent ? name.toJSON() : { text: String(name) };
206
+ }
207
+ return this.hoverEvent(HoverAction.SHOW_ENTITY, contents);
208
+ }
209
+
210
+ append(...children) {
211
+ if (!this._data.extra) {
212
+ this._data.extra = [];
213
+ }
214
+
215
+ for (const child of children) {
216
+ if (child instanceof TextComponent) {
217
+ this._data.extra.push(child.toJSON());
218
+ } else {
219
+ this._data.extra.push({ text: String(child) });
220
+ }
221
+ }
222
+
223
+ return this;
224
+ }
225
+
226
+ toJSON() {
227
+ return { ...this._data };
228
+ }
229
+
230
+ toString() {
231
+ return JSON.stringify(this._data);
232
+ }
233
+
234
+ toPlainText() {
235
+ let text = this._data.text || '';
236
+
237
+ if (this._data.extra) {
238
+ for (const extra of this._data.extra) {
239
+ if (typeof extra === 'string') {
240
+ text += extra;
241
+ } else if (extra.text) {
242
+ text += extra.text;
243
+ }
244
+ }
245
+ }
246
+
247
+ return text;
248
+ }
249
+
250
+ static fromJSON(json) {
251
+ if (typeof json === 'string') {
252
+ json = JSON.parse(json);
253
+ }
254
+
255
+ const component = new TextComponent();
256
+ component._data = { ...json };
257
+ return component;
258
+ }
259
+
260
+ static fromLegacy(legacy) {
261
+ const colorMap = {
262
+ '0': 'black', '1': 'dark_blue', '2': 'dark_green', '3': 'dark_aqua',
263
+ '4': 'dark_red', '5': 'dark_purple', '6': 'gold', '7': 'gray',
264
+ '8': 'dark_gray', '9': 'blue', 'a': 'green', 'b': 'aqua',
265
+ 'c': 'red', 'd': 'light_purple', 'e': 'yellow', 'f': 'white'
266
+ };
267
+
268
+ const formatMap = {
269
+ 'k': 'obfuscated', 'l': 'bold', 'm': 'strikethrough',
270
+ 'n': 'underlined', 'o': 'italic', 'r': 'reset'
271
+ };
272
+
273
+ const root = TextComponent.text('');
274
+ let current = TextComponent.text('');
275
+ let buffer = '';
276
+
277
+ for (let i = 0; i < legacy.length; i++) {
278
+ if (legacy[i] === '§' && i + 1 < legacy.length) {
279
+ const code = legacy[i + 1].toLowerCase();
280
+
281
+ if (buffer) {
282
+ current._data.text = buffer;
283
+ root.append(current);
284
+ buffer = '';
285
+ }
286
+
287
+ if (colorMap[code]) {
288
+ current = TextComponent.text('').color(colorMap[code]);
289
+ } else if (formatMap[code]) {
290
+ if (code === 'r') {
291
+ current = TextComponent.text('');
292
+ } else {
293
+ current = TextComponent.text('')[formatMap[code]]();
294
+ }
295
+ }
296
+
297
+ i++;
298
+ } else {
299
+ buffer += legacy[i];
300
+ }
301
+ }
302
+
303
+ if (buffer) {
304
+ current._data.text = buffer;
305
+ root.append(current);
306
+ }
307
+
308
+ return root;
309
+ }
310
+ }
311
+
312
+ export class ComponentBuilder {
313
+ constructor() {
314
+ this.components = [];
315
+ }
316
+
317
+ append(component) {
318
+ if (typeof component === 'string') {
319
+ component = TextComponent.text(component);
320
+ }
321
+ this.components.push(component);
322
+ return this;
323
+ }
324
+
325
+ newLine() {
326
+ return this.append('\n');
327
+ }
328
+
329
+ build() {
330
+ if (this.components.length === 0) {
331
+ return TextComponent.text('');
332
+ }
333
+
334
+ if (this.components.length === 1) {
335
+ return this.components[0];
336
+ }
337
+
338
+ const root = TextComponent.text('');
339
+ root.append(...this.components);
340
+ return root;
341
+ }
342
+
343
+ static create() {
344
+ return new ComponentBuilder();
345
+ }
346
+ }
347
+
348
+ export default {
349
+ ChatColor,
350
+ ChatFormat,
351
+ ClickAction,
352
+ HoverAction,
353
+ TextComponent,
354
+ ComponentBuilder
355
+ };
@@ -0,0 +1,105 @@
1
+ import * as crypto from 'crypto';
2
+
3
+ export class UUID {
4
+
5
+ constructor(mostSigBits, leastSigBits) {
6
+ this.mostSigBits = BigInt(mostSigBits);
7
+ this.leastSigBits = BigInt(leastSigBits);
8
+ }
9
+
10
+ static fromString(str) {
11
+
12
+ const hex = str.replace(/-/g, '');
13
+
14
+ if (hex.length !== 32) {
15
+ throw new Error('Invalid UUID string length');
16
+ }
17
+
18
+ const mostSigBits = BigInt('0x' + hex.substring(0, 16));
19
+ const leastSigBits = BigInt('0x' + hex.substring(16, 32));
20
+
21
+ return new UUID(mostSigBits, leastSigBits);
22
+ }
23
+
24
+ static randomUUID() {
25
+ const bytes = crypto.randomBytes(16);
26
+
27
+ bytes[6] = (bytes[6] & 0x0f) | 0x40;
28
+
29
+ bytes[8] = (bytes[8] & 0x3f) | 0x80;
30
+
31
+ const mostSigBits = bytes.readBigUInt64BE(0);
32
+ const leastSigBits = bytes.readBigUInt64BE(8);
33
+
34
+ return new UUID(mostSigBits, leastSigBits);
35
+ }
36
+
37
+ static fromBuffer(buffer, offset = 0) {
38
+ const mostSigBits = buffer.readBigUInt64BE(offset);
39
+ const leastSigBits = buffer.readBigUInt64BE(offset + 8);
40
+ return new UUID(mostSigBits, leastSigBits);
41
+ }
42
+
43
+ static fromBytes(bytes) {
44
+ return UUID.fromBuffer(Buffer.isBuffer(bytes) ? bytes : Buffer.from(bytes));
45
+ }
46
+
47
+ static offlinePlayerUUID(username) {
48
+ const hash = crypto.createHash('md5').update(`OfflinePlayer:${username}`).digest();
49
+
50
+ hash[6] = (hash[6] & 0x0f) | 0x30;
51
+
52
+ hash[8] = (hash[8] & 0x3f) | 0x80;
53
+
54
+ return UUID.fromBuffer(hash);
55
+ }
56
+
57
+ toBuffer(buffer, offset = 0) {
58
+ buffer.writeBigUInt64BE(this.mostSigBits, offset);
59
+ buffer.writeBigUInt64BE(this.leastSigBits, offset + 8);
60
+ }
61
+
62
+ toBytes() {
63
+ const buffer = Buffer.alloc(16);
64
+ this.toBuffer(buffer);
65
+ return buffer;
66
+ }
67
+
68
+ toString(withDashes = true) {
69
+ const mostHex = this.mostSigBits.toString(16).padStart(16, '0');
70
+ const leastHex = this.leastSigBits.toString(16).padStart(16, '0');
71
+
72
+ const hex = mostHex + leastHex;
73
+
74
+ if (withDashes) {
75
+ return [
76
+ hex.substring(0, 8),
77
+ hex.substring(8, 12),
78
+ hex.substring(12, 16),
79
+ hex.substring(16, 20),
80
+ hex.substring(20, 32)
81
+ ].join('-');
82
+ }
83
+
84
+ return hex;
85
+ }
86
+
87
+ equals(other) {
88
+ if (!(other instanceof UUID)) return false;
89
+ return this.mostSigBits === other.mostSigBits &&
90
+ this.leastSigBits === other.leastSigBits;
91
+ }
92
+
93
+ get version() {
94
+ return Number((this.mostSigBits >> 12n) & 0xFn);
95
+ }
96
+
97
+ get variant() {
98
+ const variantBits = Number((this.leastSigBits >> 62n) & 0x3n);
99
+ if ((variantBits & 0x2) === 0) return 0;
100
+ if ((variantBits & 0x1) === 0) return 2;
101
+ return variantBits;
102
+ }
103
+ }
104
+
105
+ export default UUID;
@@ -0,0 +1,144 @@
1
+ const SEGMENT_BITS = 0x7F;
2
+ const CONTINUE_BIT = 0x80;
3
+
4
+ export function encodeVarInt(value) {
5
+ const bytes = [];
6
+
7
+ if (value < 0) {
8
+ value = value >>> 0;
9
+ }
10
+
11
+ do {
12
+ let byte = value & SEGMENT_BITS;
13
+ value >>>= 7;
14
+
15
+ if (value !== 0) {
16
+ byte |= CONTINUE_BIT;
17
+ }
18
+
19
+ bytes.push(byte);
20
+ } while (value !== 0);
21
+
22
+ return Buffer.from(bytes);
23
+ }
24
+
25
+ export function decodeVarInt(buffer, offset = 0) {
26
+ let value = 0;
27
+ let position = 0;
28
+ let bytesRead = 0;
29
+
30
+ while (true) {
31
+ if (offset + bytesRead >= buffer.length) {
32
+ throw new Error('VarInt buffer underflow');
33
+ }
34
+
35
+ const byte = buffer[offset + bytesRead];
36
+ value |= (byte & SEGMENT_BITS) << position;
37
+ bytesRead++;
38
+
39
+ if ((byte & CONTINUE_BIT) === 0) {
40
+ break;
41
+ }
42
+
43
+ position += 7;
44
+
45
+ if (position >= 32) {
46
+ throw new Error('VarInt is too big');
47
+ }
48
+ }
49
+
50
+ if (value > 0x7FFFFFFF) {
51
+ value = value - 0x100000000;
52
+ }
53
+
54
+ return { value, bytesRead };
55
+ }
56
+
57
+ export function getVarIntSize(value) {
58
+ if (value < 0) value = value >>> 0;
59
+
60
+ if (value < 0x80) return 1;
61
+ if (value < 0x4000) return 2;
62
+ if (value < 0x200000) return 3;
63
+ if (value < 0x10000000) return 4;
64
+ return 5;
65
+ }
66
+
67
+ export function encodeVarLong(value) {
68
+ const bytes = [];
69
+ let bigValue = BigInt(value);
70
+
71
+ if (bigValue < 0n) {
72
+ bigValue = bigValue & 0xFFFFFFFFFFFFFFFFn;
73
+ }
74
+
75
+ do {
76
+ let byte = Number(bigValue & 0x7Fn);
77
+ bigValue >>= 7n;
78
+
79
+ if (bigValue !== 0n) {
80
+ byte |= CONTINUE_BIT;
81
+ }
82
+
83
+ bytes.push(byte);
84
+ } while (bigValue !== 0n);
85
+
86
+ return Buffer.from(bytes);
87
+ }
88
+
89
+ export function decodeVarLong(buffer, offset = 0) {
90
+ let value = 0n;
91
+ let position = 0n;
92
+ let bytesRead = 0;
93
+
94
+ while (true) {
95
+ if (offset + bytesRead >= buffer.length) {
96
+ throw new Error('VarLong buffer underflow');
97
+ }
98
+
99
+ const byte = buffer[offset + bytesRead];
100
+ value |= BigInt(byte & SEGMENT_BITS) << position;
101
+ bytesRead++;
102
+
103
+ if ((byte & CONTINUE_BIT) === 0) {
104
+ break;
105
+ }
106
+
107
+ position += 7n;
108
+
109
+ if (position >= 64n) {
110
+ throw new Error('VarLong is too big');
111
+ }
112
+ }
113
+
114
+ if (value > 0x7FFFFFFFFFFFFFFFn) {
115
+ value = value - 0x10000000000000000n;
116
+ }
117
+
118
+ return { value, bytesRead };
119
+ }
120
+
121
+ export function getVarLongSize(value) {
122
+ let bigValue = BigInt(value);
123
+ if (bigValue < 0n) bigValue = bigValue & 0xFFFFFFFFFFFFFFFFn;
124
+
125
+ if (bigValue < 0x80n) return 1;
126
+ if (bigValue < 0x4000n) return 2;
127
+ if (bigValue < 0x200000n) return 3;
128
+ if (bigValue < 0x10000000n) return 4;
129
+ if (bigValue < 0x800000000n) return 5;
130
+ if (bigValue < 0x40000000000n) return 6;
131
+ if (bigValue < 0x2000000000000n) return 7;
132
+ if (bigValue < 0x100000000000000n) return 8;
133
+ if (bigValue < 0x8000000000000000n) return 9;
134
+ return 10;
135
+ }
136
+
137
+ export default {
138
+ encodeVarInt,
139
+ decodeVarInt,
140
+ getVarIntSize,
141
+ encodeVarLong,
142
+ decodeVarLong,
143
+ getVarLongSize
144
+ };
@@ -0,0 +1,5 @@
1
+ export * from './VarInt.js';
2
+ export * from './UUID.js';
3
+ export * from './Position.js';
4
+ export * from './NBT.js';
5
+ export * from './TextComponent.js';