@vaitosoi/minejs 0.2.2 → 0.3.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.
Files changed (118) hide show
  1. package/assets/minecraft/26.2/packets.json +4741 -0
  2. package/dist/base/error.d.ts +29 -0
  3. package/dist/base/error.d.ts.map +1 -1
  4. package/dist/base/error.js +54 -1
  5. package/dist/base/error.js.map +1 -1
  6. package/dist/base/typing.d.ts +7 -1
  7. package/dist/base/typing.d.ts.map +1 -1
  8. package/dist/client/client.d.ts +25 -14
  9. package/dist/client/client.d.ts.map +1 -1
  10. package/dist/client/client.js +73 -35
  11. package/dist/client/client.js.map +1 -1
  12. package/dist/client/tcp.d.ts +16 -201
  13. package/dist/client/tcp.d.ts.map +1 -1
  14. package/dist/client/tcp.js +41 -706
  15. package/dist/client/tcp.js.map +1 -1
  16. package/dist/index.d.ts +12 -12
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +12 -12
  19. package/dist/index.js.map +1 -1
  20. package/dist/{translator → packet}/decoder.d.ts +1 -1
  21. package/dist/packet/decoder.d.ts.map +1 -0
  22. package/dist/{translator → packet}/decoder.js +3 -3
  23. package/dist/packet/decoder.js.map +1 -0
  24. package/dist/packet/dispatcher.d.ts +46 -0
  25. package/dist/packet/dispatcher.d.ts.map +1 -0
  26. package/dist/packet/dispatcher.js +626 -0
  27. package/dist/packet/dispatcher.js.map +1 -0
  28. package/dist/{translator → packet}/encoder.d.ts +4 -3
  29. package/dist/packet/encoder.d.ts.map +1 -0
  30. package/dist/{translator → packet}/encoder.js +18 -7
  31. package/dist/packet/encoder.js.map +1 -0
  32. package/dist/packet/static.d.ts.map +1 -0
  33. package/dist/packet/static.js.map +1 -0
  34. package/dist/{base → physics}/aabb.d.ts +2 -2
  35. package/dist/physics/aabb.d.ts.map +1 -0
  36. package/dist/{base → physics}/aabb.js +5 -5
  37. package/dist/physics/aabb.js.map +1 -0
  38. package/dist/physics/direction.d.ts.map +1 -0
  39. package/dist/physics/direction.js.map +1 -0
  40. package/dist/{base → physics}/player.d.ts +8 -5
  41. package/dist/physics/player.d.ts.map +1 -0
  42. package/dist/{base → physics}/player.js +40 -25
  43. package/dist/physics/player.js.map +1 -0
  44. package/dist/version/codec.d.ts +18 -0
  45. package/dist/version/codec.d.ts.map +1 -0
  46. package/dist/version/codec.js +214 -0
  47. package/dist/version/codec.js.map +1 -0
  48. package/dist/version/registry.d.ts +236 -0
  49. package/dist/version/registry.d.ts.map +1 -0
  50. package/dist/version/registry.js +289 -0
  51. package/dist/version/registry.js.map +1 -0
  52. package/dist/{base → world}/block.d.ts +5 -5
  53. package/dist/world/block.d.ts.map +1 -0
  54. package/dist/{base → world}/block.js +13 -13
  55. package/dist/world/block.js.map +1 -0
  56. package/dist/{base → world}/entity.d.ts +4 -4
  57. package/dist/world/entity.d.ts.map +1 -0
  58. package/dist/{base → world}/entity.js +6 -6
  59. package/dist/world/entity.js.map +1 -0
  60. package/dist/world/state.d.ts +151 -0
  61. package/dist/world/state.d.ts.map +1 -0
  62. package/dist/world/state.js +108 -0
  63. package/dist/world/state.js.map +1 -0
  64. package/dist/world/tick.d.ts.map +1 -0
  65. package/dist/world/tick.js.map +1 -0
  66. package/package.json +7 -2
  67. package/src/base/error.ts +36 -0
  68. package/src/base/typing.ts +9 -1
  69. package/src/client/client.ts +99 -42
  70. package/src/client/tcp.ts +49 -954
  71. package/src/index.ts +12 -12
  72. package/src/{translator → packet}/decoder.ts +3 -3
  73. package/src/packet/dispatcher.ts +785 -0
  74. package/src/{translator → packet}/encoder.ts +20 -9
  75. package/src/{base → physics}/aabb.ts +5 -5
  76. package/src/{base → physics}/player.ts +41 -25
  77. package/src/version/codec.ts +227 -0
  78. package/src/version/registry.ts +333 -0
  79. package/src/{base → world}/block.ts +12 -11
  80. package/src/{base → world}/entity.ts +5 -5
  81. package/src/world/state.ts +232 -0
  82. package/test/adapter/index.ts +14 -0
  83. package/test/client/index.ts +1 -1
  84. package/test/json/index.ts +3 -0
  85. package/dist/base/aabb.d.ts.map +0 -1
  86. package/dist/base/aabb.js.map +0 -1
  87. package/dist/base/block.d.ts.map +0 -1
  88. package/dist/base/block.js.map +0 -1
  89. package/dist/base/direction.d.ts.map +0 -1
  90. package/dist/base/direction.js.map +0 -1
  91. package/dist/base/entity.d.ts.map +0 -1
  92. package/dist/base/entity.js.map +0 -1
  93. package/dist/base/player.d.ts.map +0 -1
  94. package/dist/base/player.js.map +0 -1
  95. package/dist/base/registry.d.ts +0 -50
  96. package/dist/base/registry.d.ts.map +0 -1
  97. package/dist/base/registry.js +0 -89
  98. package/dist/base/registry.js.map +0 -1
  99. package/dist/base/tick.d.ts.map +0 -1
  100. package/dist/base/tick.js.map +0 -1
  101. package/dist/translator/decoder.d.ts.map +0 -1
  102. package/dist/translator/decoder.js.map +0 -1
  103. package/dist/translator/encoder.d.ts.map +0 -1
  104. package/dist/translator/encoder.js.map +0 -1
  105. package/dist/translator/static.d.ts.map +0 -1
  106. package/dist/translator/static.js.map +0 -1
  107. package/src/base/registry.ts +0 -87
  108. /package/assets/minecraft/{blocks.json → 26.2/blocks.json} +0 -0
  109. /package/assets/minecraft/{entities.json → 26.2/entities.json} +0 -0
  110. /package/dist/{translator → packet}/static.d.ts +0 -0
  111. /package/dist/{translator → packet}/static.js +0 -0
  112. /package/dist/{base → physics}/direction.d.ts +0 -0
  113. /package/dist/{base → physics}/direction.js +0 -0
  114. /package/dist/{base → world}/tick.d.ts +0 -0
  115. /package/dist/{base → world}/tick.js +0 -0
  116. /package/src/{translator → packet}/static.ts +0 -0
  117. /package/src/{base → physics}/direction.ts +0 -0
  118. /package/src/{base → world}/tick.ts +0 -0
@@ -1,8 +1,17 @@
1
- import { Vec3 } from "../base/direction";
1
+ import { Vec3 } from "../physics/direction";
2
2
  import { CONTINUATION_FLAG, CONTINUE_BIT, isFixedSizeTag, isTag, MAX_QUANTIZED_VALUE, SCALE_BITS, SEGMENT_BITS } from "./static";
3
3
  import { InvalidValue, NumberTooBig, UnexpectedValue } from "../base/error";
4
4
  import { FixedSizeTag, Tag } from "./static";
5
5
 
6
+ export function makeMovementFlag(onGround: boolean, pushingWall: boolean) {
7
+ let flag = 0;
8
+ if (onGround)
9
+ flag &= 1;
10
+ if (pushingWall)
11
+ flag |= 1 << 2;
12
+ return flag;
13
+ }
14
+
6
15
  export class BinaryEncoder {
7
16
  private buffer = Buffer.alloc(0);
8
17
 
@@ -14,8 +23,9 @@ export class BinaryEncoder {
14
23
  this.buffer = Buffer.alloc(0);
15
24
  }
16
25
 
17
- public concat(buf: Buffer) {
26
+ public writeRaw(buf: Buffer) {
18
27
  this.buffer = Buffer.concat([this.buffer, buf]);
28
+ return this;
19
29
  }
20
30
 
21
31
 
@@ -27,7 +37,7 @@ export class BinaryEncoder {
27
37
  public write(size: number, val: any, writeFunc: (buf: Buffer) => ((val: any) => void)) {
28
38
  const buf = Buffer.alloc(size);
29
39
  writeFunc(buf).bind(buf)(val);
30
- this.concat(buf);
40
+ this.writeRaw(buf);
31
41
  return this;
32
42
  }
33
43
 
@@ -129,7 +139,7 @@ export class BinaryEncoder {
129
139
  */
130
140
  public writeString(str: string) {
131
141
  this.writeVarInt(str.length);
132
- this.concat(Buffer.from(str));
142
+ this.writeRaw(Buffer.from(str));
133
143
  return this;
134
144
  }
135
145
 
@@ -171,7 +181,7 @@ export class BinaryEncoder {
171
181
  else return val;
172
182
  });
173
183
  this.writeVarInt(length);
174
- this.concat(Buffer.concat(array));
184
+ this.writeRaw(Buffer.concat(array));
175
185
  return this;
176
186
  }
177
187
 
@@ -187,7 +197,7 @@ export class BinaryEncoder {
187
197
  public writeRawPrefixedArray(data: Buffer, size: number) {
188
198
  const length = Math.ceil(data.length / size);
189
199
  this.writeVarInt(length);
190
- this.concat(data);
200
+ this.writeRaw(data);
191
201
  return this;
192
202
  }
193
203
 
@@ -224,8 +234,9 @@ export class BinaryEncoder {
224
234
  this.writeVarInt(Number(scaleFactor >> 2n));
225
235
  }
226
236
  }
227
- }
228
237
 
238
+ return this;
239
+ }
229
240
  }
230
241
 
231
242
  type CompoundField = any | {
@@ -306,7 +317,7 @@ export class NBTEncoder extends BinaryEncoder {
306
317
  public writeString(str: string) {
307
318
  this.writeUShort(str.length);
308
319
  if (str.length === 0) return this;
309
- this.concat(Buffer.from(str));
320
+ this.writeRaw(Buffer.from(str));
310
321
  return this;
311
322
  }
312
323
 
@@ -322,7 +333,7 @@ export class NBTEncoder extends BinaryEncoder {
322
333
  for (const item of arr)
323
334
  this.writeString(item);
324
335
  else
325
- this.concat(Buffer.from(arr));
336
+ this.writeRaw(Buffer.from(arr));
326
337
  return this;
327
338
  }
328
339
 
@@ -1,9 +1,9 @@
1
- import { BitSet } from "./bitset";
1
+ import { BitSet } from "../base/bitset";
2
2
  import { Axis, AxisCycle, BaseAxis, BaseVec3, Direction, Vec3 } from "./direction";
3
- import { RegistryItemNotFound } from "./error";
4
- import { EntityRegistry } from "./registry";
5
- import { Epsilon, lowerBoundBinarySearch } from "./math";
6
- import { BlockHitResult } from "./block";
3
+ import { RegistryItemNotFound } from "../base/error";
4
+ import { EntityRegistry } from "../version/registry";
5
+ import { Epsilon, lowerBoundBinarySearch } from "../base/math";
6
+ import { BlockHitResult } from "../world/block";
7
7
 
8
8
  export interface BaseAABB {
9
9
  minX: number;
@@ -1,11 +1,14 @@
1
- import { EntitiesManager } from "./entity";
1
+ import { EntitiesManager } from "../world/entity";
2
2
  import { Angle, Axis, BaseAxis, BaseVec3, Vec3 } from "./direction";
3
3
  import { AABB, Shapes, VoxelShape } from "./aabb";
4
- import { BlockGetter, BlockManager, BlockState } from "./block";
5
- import { clamp, Epsilon, equal, lerp } from "./math";
6
- import { TCPClient } from "../client/tcp";
7
- import { ClientNotReady } from "./error";
4
+ import { BlockGetter, BlockManager, BlockState } from "../world/block";
5
+ import { clamp, Epsilon, equal, lerp } from "../base/math";
6
+ import { ClientNotReady } from "../base/error";
8
7
  import { LevelHeightLimit } from "../client/static";
8
+ import { SharedState } from "../world/state";
9
+ import { TypedEmmiter } from "../base/event";
10
+ import { ClientEvents } from "../client/client";
11
+ import { makeMovementFlag } from "../packet/encoder";
9
12
 
10
13
  export enum MoveDirection {
11
14
  Forward = "W",
@@ -54,15 +57,16 @@ export class Player {
54
57
  private lastOnGround: boolean = true;
55
58
 
56
59
  constructor(
60
+ private state: SharedState,
61
+ private on: TypedEmmiter<ClientEvents>["on"],
57
62
  private entities: EntitiesManager,
58
63
  private blocks: BlockManager,
59
- private tcp: TCPClient
60
64
  ) {
61
- this.tcp.on("playerPosition", () => {
65
+ this.on("playerPosition", () => {
62
66
  this.onGround = true;
63
67
  this.horizontalCollision = false;
64
68
  this.fallDistance = 0;
65
- this.deltaMovement = new Vec3(this.tcp.player!.velocity);
69
+ this.deltaMovement = new Vec3(this.state.player!.velocity);
66
70
  });
67
71
  }
68
72
 
@@ -132,20 +136,20 @@ export class Player {
132
136
 
133
137
  /* Getting helper, from TCP client */
134
138
  private getPos() {
135
- this.tcp.checkReady();
136
- return new Vec3(this.tcp.player!.position);
139
+ this.state.checkReady();
140
+ return new Vec3(this.state.player!.position);
137
141
  }
138
142
  private setPos(pos: Vec3) {
139
- this.tcp.checkReady();
140
- this.tcp.player!.position = pos.copyBase();
143
+ this.state.checkReady();
144
+ this.state.player!.position = pos.copyBase();
141
145
  }
142
146
  private getAngle() {
143
- this.tcp.checkReady();
144
- return this.tcp.player!.angle;
147
+ this.state.checkReady();
148
+ return this.state.player!.angle;
145
149
  }
146
150
  private getDimension() {
147
- this.tcp.checkReady();
148
- return this.tcp.player!.dimension;
151
+ this.state.checkReady();
152
+ return this.state.player!.dimension;
149
153
  }
150
154
 
151
155
  private setDeltaMovement(x: number, y: number, z: number): void;
@@ -217,7 +221,7 @@ export class Player {
217
221
  * Ticking
218
222
  */
219
223
  public tick() {
220
- if (!this.tcp.isReady()) return;
224
+ if (!this.state.isReady()) return;
221
225
  if (!this.lastPos || !this.lastAngle) throw new ClientNotReady();
222
226
 
223
227
  // console.log("tick");
@@ -226,7 +230,7 @@ export class Player {
226
230
  this.aiStep();
227
231
  const { x, y, z } = this.getPos(),
228
232
  { x: xLast, y: yLast, z: zLast } = this.lastPos,
229
- { yaw: xRot, pitch: yRot } = this.getAngle(),
233
+ { yaw, yaw: xRot, pitch, pitch: yRot } = this.getAngle(),
230
234
  { yaw: xRotLast, pitch: yRotLast } = this.lastAngle;
231
235
  const deltaX = x - xLast,
232
236
  deltaY = y - yLast,
@@ -237,16 +241,28 @@ export class Player {
237
241
  const move = new Vec3(deltaX, deltaY, deltaZ).lengthSqr() > (2e-4 * 2e-4) || this.positionReminder > 20,
238
242
  rot = deltaXRot !== 0 || deltaYRot !== 0;
239
243
  if (move && rot)
240
- this.tcp.sendPlayerPosRot(this.getPos(), this.getAngle(), this.onGround, this.horizontalCollision);
244
+ this.state.enqueuePacket("move_player_pos_rot", {
245
+ x, feet_y: y, z,
246
+ yaw, pitch,
247
+ flags: makeMovementFlag(this.onGround, this.horizontalCollision)
248
+ });
241
249
  else if (move)
242
- this.tcp.sendPlayerPos(this.getPos(), this.onGround, this.horizontalCollision);
250
+ this.state.enqueuePacket("move_player_pos", {
251
+ x, feet_y: y, z,
252
+ flags: makeMovementFlag(this.onGround, this.horizontalCollision)
253
+ });
243
254
  else if (rot)
244
- this.tcp.sendPlayerRot(this.getAngle(), this.onGround, this.horizontalCollision);
255
+ this.state.enqueuePacket("move_player_rot", {
256
+ yaw, pitch,
257
+ flags: makeMovementFlag(this.onGround, this.horizontalCollision)
258
+ });
245
259
  else if (
246
260
  this.onGround !== this.lastOnGround ||
247
261
  this.horizontalCollision !== this.lastHorizontalCollision
248
262
  )
249
- this.tcp.sendPlayerStatus(this.onGround, this.horizontalCollision);
263
+ this.state.enqueuePacket("move_player_status_only", {
264
+ flags: makeMovementFlag(this.onGround, this.horizontalCollision)
265
+ });
250
266
 
251
267
  if (move) {
252
268
  this.lastPos = this.getPos();
@@ -503,7 +519,7 @@ export class Player {
503
519
 
504
520
  private collide(movement: Vec3): Vec3 {
505
521
  // Get player's bounding box
506
- const { x: playerX, y: playerY, z: playerZ } = this.tcp.player!.position;
522
+ const { x: playerX, y: playerY, z: playerZ } = this.state.player!.position;
507
523
  const playerBB = AABB.fromEntityType("minecraft:player")
508
524
  .move(playerX, playerY, playerZ);
509
525
  const expandedBB = playerBB.expandTowards(movement);
@@ -515,7 +531,7 @@ export class Player {
515
531
  // });
516
532
 
517
533
  // Collect all colliders
518
- const colliders = this.collectColliders(expandedBB, [this.tcp.player!.entityId]);
534
+ const colliders = this.collectColliders(expandedBB, [this.state.player!.entityId]);
519
535
  // // console.log('nonEmptyColliders', colliders.filter(c => !c.isEmpty()).length);
520
536
 
521
537
  // Get the farest distance can move
@@ -535,7 +551,7 @@ export class Player {
535
551
  if (!onGroundAfterCollision)
536
552
  stepUpAABB = stepUpAABB.expandTowards(0, -1e-5, 0);
537
553
 
538
- const colliders = this.collectColliders(stepUpAABB, [this.tcp.player!.entityId]);
554
+ const colliders = this.collectColliders(stepUpAABB, [this.state.player!.entityId]);
539
555
  const stepHeightToSkip = movementStep.y;
540
556
  const stepUpCandidateSet: Set<number> = new Set();
541
557
  for (const collider of colliders) {
@@ -0,0 +1,227 @@
1
+ import z, { file } from "zod";
2
+ import { MissingField, MissingPacketField, UnexpectedValue } from "../base/error";
3
+ import { BinaryDecoder } from "../packet/decoder";
4
+ import { ConnectionState, SharedState } from "../world/state";
5
+ import { FieldNode, PacketObject, PacketRegistry, VersionDefinitions } from "./registry";
6
+ import { Dispatcher } from "../packet/dispatcher";
7
+ import { BinaryEncoder } from "../packet/encoder";
8
+
9
+ const TCPStateMapping: Record<ConnectionState, keyof z.infer<typeof VersionDefinitions> | null> = {
10
+ [ConnectionState.Disconnected]: null,
11
+ [ConnectionState.Handshake]: "handshaking",
12
+ [ConnectionState.Login]: "login",
13
+ [ConnectionState.Configure]: "configuration",
14
+ [ConnectionState.Play]: "play",
15
+ };
16
+
17
+ export interface EncodeResult {
18
+ buffer: Buffer,
19
+ packet: z.infer<typeof PacketObject>,
20
+ }
21
+
22
+ export class VersionCodec {
23
+ constructor(private readonly state: SharedState) { }
24
+
25
+ public consumePacket: (packetId: string, data: object) => void = (...args) => { throw new Error("method not implemented"); };
26
+
27
+ public handlePacket(packetId: number, decoder: BinaryDecoder) {
28
+ const mappedState = TCPStateMapping[this.state.state];
29
+ if (!mappedState) return; // console.log("no state");
30
+ const packet = PacketRegistry.getPacket(mappedState, "clientbound", packetId);
31
+ if (!packet) return; // console.log("no packet");
32
+
33
+ const { name, structure, skipForNow } = packet;
34
+ if (skipForNow) return;
35
+ // console.log(`> packet ${name}`);
36
+ const resolvedObject: Record<string, any> = {};
37
+ for (const [name, field] of Object.entries(structure)) {
38
+ // console.log({ name, resolvedObject });
39
+ resolvedObject[name] = this.readField(packetId, resolvedObject, name, field, decoder);
40
+ }
41
+
42
+ this.consumePacket(`${TCPStateMapping[this.state.state]}:${name}`, resolvedObject);
43
+ }
44
+
45
+ public encodePacket(packetId: number | string, data: Record<string, any>): EncodeResult {
46
+ const mappedState = TCPStateMapping[this.state.state];
47
+ if (!mappedState) throw new UnexpectedValue("map-able state", this.state.state.toString());
48
+ const packet = PacketRegistry.getPacket(mappedState, "serverbound", packetId);
49
+ if (!packet) throw new UnexpectedValue("valid serverbound packet id", packetId.toString());
50
+
51
+ const { name: packetName, structure } = packet;
52
+ let encoder = new BinaryEncoder();
53
+ for (const [name, field] of Object.entries(structure)) {
54
+ if (!(name in data))
55
+ throw new MissingField(name, `packet ${packetName}`);
56
+ if (typeof data[name] === "object")
57
+ if ("value" in data[name])
58
+ if ("metadata" in data[name])
59
+ encoder = this.writeField(field, encoder, data[name]["value"], data[name]["metadata"]);
60
+ else if ("length" in data[name])
61
+ encoder = this.writeField(field, encoder, data[name]["value"], { length: data[name]["length"] });
62
+ else
63
+ encoder = this.writeField(field, encoder, data[name]["value"]);
64
+ else
65
+ encoder = this.writeField(field, encoder, data[name]);
66
+ else
67
+ encoder = this.writeField(field, encoder, data[name]);
68
+ }
69
+ return { buffer: encoder.getBuffer(), packet };
70
+ }
71
+
72
+ private readField(
73
+ // Current reading state
74
+ packetId: number,
75
+ readObject: Record<string, any>,
76
+
77
+ // Current field
78
+ fieldName: string,
79
+ field: FieldNode,
80
+ decoder: BinaryDecoder
81
+ ): any {
82
+ switch (field.type) {
83
+ case "string": return decoder.readString();
84
+ case "boolean": return decoder.readBoolean();
85
+ case "byte": return decoder.readByte();
86
+ case "unsigned_byte": return decoder.readUByte();
87
+ case "short": return decoder.readShort();
88
+ case "unsigned_short": return decoder.readUShort();
89
+ case "int": return decoder.readInt();
90
+ case "long": return decoder.readLong();
91
+ case "float": return decoder.readFloat();
92
+ case "double": return decoder.readDouble();
93
+ case "var_int": return decoder.readVarInt();
94
+ case "var_long": return decoder.readVarLong();
95
+ case "uuid": return decoder.readUUID();
96
+ case "position": return decoder.readPosition();
97
+ case "array": {
98
+ let length;
99
+ if (!isNaN(Number(field.length)))
100
+ length = Number(field.length);
101
+ else
102
+ length = readObject[field.length];
103
+ if (length === undefined) throw new MissingPacketField(packetId, fieldName, field.length.toString());
104
+ return decoder.readArray(length, (decoder) => this.readField(packetId, readObject, fieldName, field.subType, decoder));
105
+ }
106
+ case "prefixed_array": return decoder.readPrefixedArray((decoder) => this.readField(packetId, readObject, fieldName, field.subType, decoder));
107
+ case "teleport_flag": return decoder.readTeleportFlag();
108
+ case "prefixed_optional": return decoder.readPrefixedOptional((decoder) => this.readField(packetId, readObject, fieldName, field.subType, decoder));
109
+ case "nbt": return decoder.readNBT();
110
+ case "lpvec3": return decoder.readLpVec3();
111
+ case "fixed_point": {
112
+ const value = this.readField(packetId, readObject, fieldName, field.subType, decoder);
113
+ return decoder.readFixedPoint(value, field.fractionBits);
114
+ }
115
+ case "angle": return decoder.readAngle();
116
+ case "id_or_x": return decoder.readIdOrX((decoder) => this.readField(packetId, readObject, fieldName, field.subType, decoder));
117
+ case "chat_type_decoration": return decoder.readChatTypeDecoration();
118
+ case "chat_type": return decoder.readChatType();
119
+ case "enum": return this.readField(packetId, readObject, fieldName, field.subType, decoder);
120
+ case "json_text": return JSON.parse(decoder.readString());
121
+ case "object": {
122
+ const obj: Record<string, any> = {};
123
+ for (const [key, type] of Object.entries(field.fields))
124
+ obj[key] = this.readField(packetId, readObject, key, type, decoder);
125
+ return obj;
126
+ }
127
+ case "game_profile": {
128
+ return {
129
+ uuid: decoder.readUUID(),
130
+ username: decoder.readString(),
131
+ pproperties: decoder.readPrefixedArray((decoder) => ({
132
+ name: decoder.readString(),
133
+ value: decoder.readString(),
134
+ signature: decoder.readPrefixedOptional((decoder) => decoder.readString())
135
+ }))
136
+ };
137
+ }
138
+ case "heightmap": {
139
+ return {
140
+ type: decoder.readVarInt(),
141
+ data: decoder.readPrefixedArray((decoder) => decoder.readLong())
142
+ };
143
+ }
144
+ case "bitset": return decoder.readPrefixedArray((decoder) => decoder.readLong());
145
+ case "teleport_flags": return decoder.readTeleportFlag();
146
+ case "null": return null;
147
+ case "switch": {
148
+ if (!(field.dependsOn in readObject)) throw new MissingPacketField(packetId, fieldName, field.dependsOn);
149
+ const dependencyValue = readObject[field.dependsOn];
150
+ for (const [value, type] of field.cases)
151
+ if (dependencyValue === value)
152
+ return this.readField(packetId, readObject, fieldName, type, decoder);
153
+ if (field.default)
154
+ return this.readField(packetId, readObject, fieldName, field.default, decoder);
155
+ return null;
156
+ }
157
+ }
158
+ }
159
+
160
+
161
+ private writeField(
162
+ field: FieldNode,
163
+ encoder: BinaryEncoder,
164
+ value: any,
165
+ metadata: Record<string, any> = {}
166
+ ): BinaryEncoder {
167
+ switch (field.type) {
168
+ case "string": return encoder.writeString(value);
169
+ case "boolean": return encoder.writeBoolean(value);
170
+ case "byte": return encoder.writeByte(value);
171
+ case "unsigned_byte": return encoder.writeUByte(value);
172
+ case "short": return encoder.writeShort(value);
173
+ case "unsigned_short": return encoder.writeUShort(value);
174
+ case "int": return encoder.writeInt(value);
175
+ case "long": return encoder.writeLong(value);
176
+ case "float": return encoder.writeFloat(value);
177
+ case "double": return encoder.writeDouble(value);
178
+ case "var_int": return encoder.writeVarInt(value);
179
+ case "var_long": return encoder.writeVarLong(value);
180
+ case "uuid": return encoder.writeRaw(value);
181
+ case "position": return encoder.writePosition(value);
182
+ // case "array": {
183
+ // const length = metadata["length"];
184
+ // // if (!length) throw new MissingField(packetId, fieldName, field.length);
185
+ // return encoder.writeArray(length, (decoder) => this.readField(packetId, readObject, fieldName, field.subType, decoder));
186
+ // }
187
+ case "prefixed_array": {
188
+ const length = metadata["length"];
189
+ if (!length) throw new MissingField("length", "prefixed array metadata object");
190
+ if (!Array.isArray(value))
191
+ throw new UnexpectedValue("an array for prefixed array", typeof value);
192
+ return encoder.writePrefixedArray(length, (encoder, index) => this.writeField(field.subType, encoder, value[index], metadata));
193
+ }
194
+ // case "teleport_flag": return encoder.writeTeleportFlag();
195
+ // case "prefixed_optional": return encoder.writePrefixedOptional((decoder) => this.readField(packetId, readObject, fieldName, field.subType, decoder));
196
+ // case "nbt": return encoder.writeNBT(value);
197
+ case "lpvec3": return encoder.writeLpVec3(value);
198
+ // case "fixed_point": {
199
+ // const value = this.readField(packetId, readObject, fieldName, field.subType, encoder);
200
+ // return encoder.writeFixedPoint(value, field.fractionBits);
201
+ // }
202
+ // case "angle": return encoder.writeAngle();
203
+ // case "id_or_x": return encoder.writeIdOrX((decoder) => this.readField(packetId, readObject, fieldName, field.subType, decoder));
204
+ // case "chat_type_decoration": return encoder.writeChatTypeDecoration();
205
+ // case "chat_type": return encoder.writeChatType();
206
+ case "enum": return this.writeField(field.subType, encoder, value, metadata);
207
+ case "json_text": return encoder.writeString(JSON.parse(value));
208
+ case "object": {
209
+ for (const [name, subField] of Object.entries(field.fields))
210
+ encoder = this.writeField(subField, encoder, value[name], metadata);
211
+ return encoder;
212
+ }
213
+ // case "switch": {
214
+ // const dependencyValue = readObject[field.dependsOn];
215
+ // if (!dependencyValue) throw new MissingField(packetId, fieldName, field.dependsOn);
216
+ // for (const [value, type] of field.cases)
217
+ // if (dependencyValue === value)
218
+ // return this.readField(packetId, readObject, fieldName, type, encoder);
219
+ // if (field.default)
220
+ // return this.readField(packetId, readObject, fieldName, field.default, encoder);
221
+ // break;
222
+ // }
223
+ default:
224
+ throw new UnexpectedValue("encoding type", field.type);
225
+ }
226
+ }
227
+ }