@vaitosoi/minejs 0.6.0 → 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.
Files changed (60) hide show
  1. package/README.md +23 -11
  2. package/assets/minecraft/26.2/packets.json +0 -12
  3. package/assets/minecraft/26.3/packets.json +228 -38
  4. package/dist/binary/encoder.d.ts.map +1 -1
  5. package/dist/binary/encoder.js +4 -4
  6. package/dist/binary/encoder.js.map +1 -1
  7. package/dist/client/client.d.ts +127 -28
  8. package/dist/client/client.d.ts.map +1 -1
  9. package/dist/client/client.js +108 -27
  10. package/dist/client/client.js.map +1 -1
  11. package/dist/net/tcp.d.ts +0 -7
  12. package/dist/net/tcp.d.ts.map +1 -1
  13. package/dist/net/tcp.js +12 -18
  14. package/dist/net/tcp.js.map +1 -1
  15. package/dist/packet/listener.d.ts +1 -1
  16. package/dist/packet/listener.d.ts.map +1 -1
  17. package/dist/packet/listener.js +142 -55
  18. package/dist/packet/listener.js.map +1 -1
  19. package/dist/packet/sender.d.ts +2 -1
  20. package/dist/packet/sender.d.ts.map +1 -1
  21. package/dist/packet/sender.js +17 -6
  22. package/dist/packet/sender.js.map +1 -1
  23. package/dist/physics/aabb.d.ts.map +1 -1
  24. package/dist/physics/aabb.js +10 -2
  25. package/dist/physics/aabb.js.map +1 -1
  26. package/dist/physics/direction.js +2 -2
  27. package/dist/physics/direction.js.map +1 -1
  28. package/dist/version/codec.d.ts.map +1 -1
  29. package/dist/version/codec.js +38 -0
  30. package/dist/version/codec.js.map +1 -1
  31. package/dist/version/registry.d.ts +6 -1
  32. package/dist/version/registry.d.ts.map +1 -1
  33. package/dist/version/registry.js +26 -3
  34. package/dist/version/registry.js.map +1 -1
  35. package/dist/world/block.d.ts +44 -2
  36. package/dist/world/block.d.ts.map +1 -1
  37. package/dist/world/block.js +61 -21
  38. package/dist/world/block.js.map +1 -1
  39. package/dist/world/entity.d.ts +3 -0
  40. package/dist/world/entity.d.ts.map +1 -1
  41. package/dist/world/entity.js +3 -0
  42. package/dist/world/entity.js.map +1 -1
  43. package/dist/world/state.d.ts +3 -0
  44. package/dist/world/state.d.ts.map +1 -1
  45. package/dist/world/state.js +9 -0
  46. package/dist/world/state.js.map +1 -1
  47. package/package.json +2 -2
  48. package/src/binary/encoder.ts +5 -6
  49. package/src/client/client.ts +174 -51
  50. package/src/net/tcp.ts +12 -18
  51. package/src/packet/listener.ts +172 -70
  52. package/src/packet/sender.ts +18 -7
  53. package/src/physics/aabb.ts +11 -2
  54. package/src/physics/direction.ts +2 -2
  55. package/src/version/codec.ts +32 -0
  56. package/src/version/registry.ts +35 -5
  57. package/src/world/block.ts +64 -22
  58. package/src/world/entity.ts +3 -0
  59. package/src/world/state.ts +10 -0
  60. package/test/client/index.ts +13 -6
@@ -56,7 +56,7 @@ export class Listener {
56
56
  "play:add_entity": this.handleSpawnEntity,
57
57
  "play:move_entity_pos": this.handleUpdateEntityPosition,
58
58
  "play:move_entity_pos_rot": this.handleUpdateEntityPositionRotation,
59
- "play:entity_position_sync": this.handleTeleportEntity,
59
+ "play:entity_position_sync": this.handleEntityPositionSync,
60
60
  "play:player_position": this.handleSynchronizePlayerPosition,
61
61
  "play:update_mob_effect": this.handleUpdateMobEffect,
62
62
  "play:remove_entities": this.handleRemoveEntity,
@@ -315,8 +315,8 @@ export class Listener {
315
315
  angle: newAngle,
316
316
  } satisfies ClientPlayer as any
317
317
  );
318
- this.state.enqueueEvent("playerPosition", { x: newPosX, y: newPosY, z: newPosZ });
319
- this.sender.sendConfirmTeleportation(teleport_id);
318
+ this.state.enqueueEvent("playerPosition", newPosition);
319
+ this.sender.sendConfirmTeleportation(teleport_id, newPosition, newAngle);
320
320
  this.sender.sendPacket("move_player_pos_rot", {
321
321
  x: newPosition.x,
322
322
  feet_y: newPosition.y,
@@ -523,89 +523,191 @@ export class Listener {
523
523
  this.state.enqueueEvent("spawnEntity", entity);
524
524
  }
525
525
 
526
- private handleTeleportEntity(data: object) {
527
- const {
528
- entity_id,
529
- x,
530
- y,
531
- z,
532
- velocity_x,
533
- velocity_y,
534
- velocity_z,
535
- pitch,
536
- yaw
537
- } = zodParse(data, zod.object({
538
- entity_id: zod.int(),
539
- x: zod.number(),
540
- y: zod.number(),
541
- z: zod.number(),
542
- velocity_x: zod.number(),
543
- velocity_y: zod.number(),
544
- velocity_z: zod.number(),
545
- pitch: zod.number(),
546
- yaw: zod.number(),
547
- }));
526
+ private handleEntityPositionSync(data: object) {
527
+ if (this.state.getProtocolId() > 776) {
548
528
 
549
- if (entity_id in this.state.world!.entities) this.state.enqueueMutation(state => {
550
- state.world!.entities[entity_id]!.position = { x, y, z };
551
- state.world!.entities[entity_id]!.velocity = { x: velocity_x, y: velocity_y, z: velocity_z };
552
- state.world!.entities[entity_id]!.angle = { pitch, yaw };
553
- });
554
- this.state.enqueueEvent("updateEntity", entity_id);
529
+ const {
530
+ entity_id,
531
+ linear,
532
+ stepped,
533
+ pitch,
534
+ yaw
535
+ } = zodParse(data, zod.object({
536
+ entity_id: zod.int(),
537
+ linear: zod.object({
538
+ x: zod.number(),
539
+ y: zod.number(),
540
+ z: zod.number(),
541
+ }).nullable(),
542
+ stepped: zod.object({
543
+ x: zod.number(),
544
+ y: zod.number(),
545
+ z: zod.number(),
546
+ tick_offset: zod.number()
547
+ }).array().nullable(),
548
+ pitch: zod.number(),
549
+ yaw: zod.number(),
550
+ }));
551
+ const { x, y, z } = linear ? linear : stepped![stepped!.length - 1]!;
552
+
553
+ if (entity_id in this.state.world!.entities) this.state.enqueueMutation(state => {
554
+ state.world!.entities[entity_id]!.position = { x, y, z };
555
+ state.world!.entities[entity_id]!.angle = { pitch, yaw };
556
+ });
557
+ this.state.enqueueEvent("updateEntity", entity_id);
558
+ } else {
559
+ const {
560
+ entity_id,
561
+ x,
562
+ y,
563
+ z,
564
+ velocity_x,
565
+ velocity_y,
566
+ velocity_z,
567
+ pitch,
568
+ yaw
569
+ } = zodParse(data, zod.object({
570
+ entity_id: zod.int(),
571
+ x: zod.number(),
572
+ y: zod.number(),
573
+ z: zod.number(),
574
+ velocity_x: zod.number(),
575
+ velocity_y: zod.number(),
576
+ velocity_z: zod.number(),
577
+ pitch: zod.number(),
578
+ yaw: zod.number(),
579
+ }));
580
+
581
+ if (entity_id in this.state.world!.entities) this.state.enqueueMutation(state => {
582
+ state.world!.entities[entity_id]!.position = { x, y, z };
583
+ state.world!.entities[entity_id]!.velocity = { x: velocity_x, y: velocity_y, z: velocity_z };
584
+ state.world!.entities[entity_id]!.angle = { pitch, yaw };
585
+ });
586
+ this.state.enqueueEvent("updateEntity", entity_id);
587
+ }
555
588
  }
556
589
 
557
590
  private handleUpdateEntityPosition(data: object) {
558
- const {
559
- entity_id,
560
- delta_x,
561
- delta_y,
562
- delta_z
563
- } = zodParse(data, zod.object({
564
- entity_id: zod.number(),
565
- delta_x: zod.number(),
566
- delta_y: zod.number(),
567
- delta_z: zod.number(),
568
- }));
591
+ if (this.state.getProtocolId() <= 776) { // Before 26.3
592
+ const {
593
+ entity_id,
594
+ delta_x,
595
+ delta_y,
596
+ delta_z
597
+ } = zodParse(data, zod.object({
598
+ entity_id: zod.number(),
599
+ delta_x: zod.number(),
600
+ delta_y: zod.number(),
601
+ delta_z: zod.number(),
602
+ }));
569
603
 
570
- if (entity_id in this.state.world!.entities) this.state.enqueueMutation(state => {
571
- let { x, y, z } = state.world!.entities[entity_id]!.position;
572
- x += delta_x;
573
- y += delta_y;
574
- z += delta_z;
575
- state.world!.entities[entity_id]!.position = { x, y, z };
576
- });
577
- this.state.enqueueEvent("updateEntity", entity_id);
578
- }
604
+ if (entity_id in this.state.world!.entities) this.state.enqueueMutation(state => {
605
+ let { x, y, z } = state.world!.entities[entity_id]!.position;
606
+ x += delta_x;
607
+ y += delta_y;
608
+ z += delta_z;
609
+ state.world!.entities[entity_id]!.position = { x, y, z };
610
+ });
611
+ this.state.enqueueEvent("updateEntity", entity_id);
612
+ } else {
613
+ const {
614
+ entity_id,
615
+ step,
616
+ steps
617
+ } = zodParse(data, zod.object({
618
+ entity_id: zod.number(),
619
+ step: zod.object({
620
+ delta_x: zod.number(),
621
+ delta_y: zod.number(),
622
+ delta_z: zod.number(),
623
+ }).nullable(),
624
+ steps: zod.object({
625
+ tick_offset: zod.number(),
626
+ delta_x: zod.number(),
627
+ delta_y: zod.number(),
628
+ delta_z: zod.number(),
629
+ }).array().nullable()
630
+ }));
631
+ const { delta_x, delta_y, delta_z } = step ? step : steps![steps!.length - 1]!;
579
632
 
580
- private handleUpdateEntityPositionRotation(data: object) {
581
- const {
582
- entity_id,
583
- delta_x,
584
- delta_y,
585
- delta_z,
586
- pitch,
587
- yaw
588
- } = zodParse(data, zod.object({
589
- entity_id: zod.number(),
590
- delta_x: zod.number(),
591
- delta_y: zod.number(),
592
- delta_z: zod.number(),
593
- pitch: zod.number(),
594
- yaw: zod.number(),
595
- }));
596
- if (entity_id in this.state.world!.entities) {
597
- this.state.enqueueMutation(state => {
633
+ if (entity_id in this.state.world!.entities) this.state.enqueueMutation(state => {
598
634
  let { x, y, z } = state.world!.entities[entity_id]!.position;
599
635
  x += delta_x;
600
636
  y += delta_y;
601
637
  z += delta_z;
602
638
  state.world!.entities[entity_id]!.position = { x, y, z };
603
- state.world!.entities[entity_id]!.angle = { yaw, pitch };
604
639
  });
605
640
  this.state.enqueueEvent("updateEntity", entity_id);
606
641
  }
607
642
  }
608
643
 
644
+ private handleUpdateEntityPositionRotation(data: object) {
645
+ if (this.state.getProtocolId() <= 776) { // Before 26.3
646
+ const {
647
+ entity_id,
648
+ delta_x,
649
+ delta_y,
650
+ delta_z,
651
+ pitch,
652
+ yaw
653
+ } = zodParse(data, zod.object({
654
+ entity_id: zod.number(),
655
+ delta_x: zod.number(),
656
+ delta_y: zod.number(),
657
+ delta_z: zod.number(),
658
+ pitch: zod.number(),
659
+ yaw: zod.number(),
660
+ }));
661
+ if (entity_id in this.state.world!.entities) {
662
+ this.state.enqueueMutation(state => {
663
+ let { x, y, z } = state.world!.entities[entity_id]!.position;
664
+ x += delta_x;
665
+ y += delta_y;
666
+ z += delta_z;
667
+ state.world!.entities[entity_id]!.position = { x, y, z };
668
+ state.world!.entities[entity_id]!.angle = { yaw, pitch };
669
+ });
670
+ this.state.enqueueEvent("updateEntity", entity_id);
671
+ }
672
+ } else {
673
+ const {
674
+ entity_id,
675
+ step,
676
+ steps,
677
+ pitch,
678
+ yaw
679
+ } = zodParse(data, zod.object({
680
+ entity_id: zod.number(),
681
+ step: zod.object({
682
+ delta_x: zod.number(),
683
+ delta_y: zod.number(),
684
+ delta_z: zod.number(),
685
+ }).nullable(),
686
+ steps: zod.object({
687
+ tick_offset: zod.number(),
688
+ delta_x: zod.number(),
689
+ delta_y: zod.number(),
690
+ delta_z: zod.number(),
691
+ }).array().nullable(),
692
+ pitch: zod.number(),
693
+ yaw: zod.number(),
694
+ }));
695
+ const { delta_x, delta_y, delta_z } = step ? step : steps![steps!.length - 1]!;
696
+
697
+ if (entity_id in this.state.world!.entities) {
698
+ this.state.enqueueMutation(state => {
699
+ let { x, y, z } = state.world!.entities[entity_id]!.position;
700
+ x += delta_x;
701
+ y += delta_y;
702
+ z += delta_z;
703
+ state.world!.entities[entity_id]!.position = { x, y, z };
704
+ state.world!.entities[entity_id]!.angle = { yaw, pitch };
705
+ });
706
+ this.state.enqueueEvent("updateEntity", entity_id);
707
+ }
708
+ }
709
+ }
710
+
609
711
  private handleSetEntityVelocity(data: object) {
610
712
  const { entity_id, velocity } = zodParse(data, zod.object({
611
713
  entity_id: zod.number(),
@@ -6,7 +6,7 @@ import { ClientStatus, ConnectionState, ServerKnownPack, SharedState } from "../
6
6
  import { sliceBuffer } from "../base/buffer";
7
7
  import { randomUUIDBytes } from "../base/math";
8
8
  import { Angle, BaseVec3, Direction } from "../physics/direction";
9
- import { MessageTooLong, NotImplemented } from "../base/error";
9
+ import { MessageTooLong, MissingField, NotImplemented } from "../base/error";
10
10
  import BitSet from "../base/bitset";
11
11
  import { makeMovementFlag } from "../binary/encoder";
12
12
  import { BlockFace } from "../world/block";
@@ -98,10 +98,22 @@ export class Sender {
98
98
  });
99
99
  }
100
100
 
101
- public sendConfirmTeleportation(teleportId: number) {
102
- this.sendPacket("accept_teleportation", {
103
- teleport_id: teleportId
104
- });
101
+ public sendConfirmTeleportation(teleportId: number): void;
102
+ public sendConfirmTeleportation(teleportId: number, newPos: BaseVec3, newAngle: Angle): void;
103
+ public sendConfirmTeleportation(teleportId: number, newPos?: BaseVec3, newAngle?: Angle) {
104
+ if (this.state.getProtocolId() > 776) {
105
+ if (!newPos || !newAngle) throw new MissingField("newPos or newAngle", "confirm_teleportation packet on version 26.3 or over");
106
+ const { x, y, z } = newPos,
107
+ { yaw, pitch } = newAngle;
108
+ this.sendPacket("accept_teleportation", {
109
+ teleport_id: teleportId,
110
+ x, y, z,
111
+ yaw, pitch
112
+ });
113
+ } else
114
+ this.sendPacket("accept_teleportation", {
115
+ teleport_id: teleportId
116
+ });
105
117
  }
106
118
 
107
119
  public sendKeepAlive(id: bigint) {
@@ -185,7 +197,6 @@ export class Sender {
185
197
  cursorPositionOnBlock: BaseVec3,
186
198
  isInsideBlock: boolean,
187
199
  worldBorderHit: boolean,
188
- sequence: number = randomInt(1024),
189
200
  ) {
190
201
  const face_ = (face instanceof Direction ? face.index3D : face) as number;
191
202
  this.sendPacket("use_item_on", {
@@ -197,7 +208,7 @@ export class Sender {
197
208
  cursor_position_z: cursorPositionOnBlock.z,
198
209
  inside_block: isInsideBlock,
199
210
  world_border_hit: worldBorderHit,
200
- sequence
211
+ sequence: this.state.nextSequence()
201
212
  });
202
213
  }
203
214
  }
@@ -585,13 +585,22 @@ export class VoxelShape {
585
585
  }
586
586
  private forAllBoxes(consumer: (bb: BaseAABB) => void, mergeNeighbor: boolean) {
587
587
  const shape = this.copy();
588
+ const consumerWithRawInd = (bb: BaseAABB) =>
589
+ consumer({
590
+ minX: shape.xs[bb.minX]!,
591
+ maxX: shape.xs[bb.maxX]!,
592
+ minY: shape.ys[bb.minY]!,
593
+ maxY: shape.ys[bb.maxY]!,
594
+ minZ: shape.zs[bb.minZ]!,
595
+ maxZ: shape.zs[bb.maxZ]!
596
+ });
588
597
  for (let y = 0; y < shape.getSize(BaseAxis.Y); y++)
589
598
  for (let x = 0; x < shape.getSize(BaseAxis.X); x++) {
590
599
  let lastStartZ = -1;
591
600
  for (let z = 0; z <= shape.getSize(BaseAxis.Z); z++) {
592
601
  if (shape.isFullWide(x, y, z)) {
593
602
  if (!mergeNeighbor)
594
- consumer({
603
+ consumerWithRawInd({
595
604
  minX: x,
596
605
  maxX: x + 1,
597
606
  minY: y,
@@ -615,7 +624,7 @@ export class VoxelShape {
615
624
  }
616
625
  endY++;
617
626
  }
618
- consumer({
627
+ consumerWithRawInd({
619
628
  minX: x,
620
629
  maxX: endX + 1,
621
630
  minY: y,
@@ -17,7 +17,7 @@ export class Vec3 implements BaseVec3 {
17
17
  * Helper function for loading vec3 args
18
18
  */
19
19
  static loadArgs(a: BaseVec3 | number, b?: number, c?: number): BaseVec3 {
20
- let x = 1, y = 1, z = 1;
20
+ let x = 0, y = 0, z = 0;
21
21
  if (typeof a === "object" && "x" in a) {
22
22
  x = a.x;
23
23
  y = a.y;
@@ -114,7 +114,7 @@ export class Vec3 implements BaseVec3 {
114
114
  public multiply(x: number, y: number, z: number): Vec3;
115
115
  public multiply(a: BaseVec3 | number, b?: number, c?: number) {
116
116
  let vec: BaseVec3;
117
- if ((a && b && c) || (typeof a === "object" && "x" in a)) vec = Vec3.loadArgs(a, b, c);
117
+ if ((a !== undefined && b !== undefined && c !== undefined) || (typeof a === "object" && "x" in a)) vec = Vec3.loadArgs(a, b, c);
118
118
  else vec = { x: a, y: a, z: a };
119
119
  const x = this.x * vec.x;
120
120
  const y = this.y * vec.y;
@@ -112,6 +112,21 @@ export class VersionCodec {
112
112
  field: FieldNode,
113
113
  decoder: BinaryDecoder
114
114
  ): any {
115
+ // if (
116
+ // this.state.clientOptions.debug &&
117
+ // this.state.clientOptions.debug.packetLogger &&
118
+ // (
119
+ // (Array.isArray(this.state.clientOptions.debug.ignoreTCPPacketLogs) && !this.state.clientOptions.debug.ignoreTCPPacketLogs.includes(packetId)) ||
120
+ // (!this.state.clientOptions.debug.ignoreTCPPacketLogs)
121
+ // )
122
+ // )
123
+ // console.dir({
124
+ // packetId,
125
+ // readObject,
126
+ // fieldName,
127
+ // field,
128
+ // decoder
129
+ // }, { depth: null });
115
130
  switch (field.type) {
116
131
  case "string": return decoder.readString();
117
132
  case "boolean": return decoder.readBoolean();
@@ -186,6 +201,23 @@ export class VersionCodec {
186
201
  throw new SkippableNotImplemented();
187
202
  throw new NotImplemented();
188
203
  }
204
+ case "infer": {
205
+ const args = field.args?.map(val =>
206
+ typeof val === "number"
207
+ ? val
208
+ : val.startsWith("literal:")
209
+ ? val.slice(8)
210
+ : readObject[val]
211
+ ) || [];
212
+ let func: (...args: any[]) => any = () => undefined;
213
+ switch (field.function) {
214
+ case "bit_and": func = (a: number, b: number) => a & b; break;
215
+ case "bit_or": func = (a: number, b: number) => a | b; break;
216
+ case "shift_left": func = (val: number, pos: number) => val << pos; break;
217
+ case "shift_right": func = (val: number, pos: number) => val >>> pos; break;
218
+ }
219
+ return func(...args);
220
+ }
189
221
  case "switch": {
190
222
  if (!(field.dependsOn in readObject)) throw new MissingPacketField(packetId, fieldName, field.dependsOn);
191
223
  const dependencyValue = readObject[field.dependsOn];
@@ -204,6 +204,7 @@ export const SupportTypes = z.enum([
204
204
  "slot",
205
205
  "null", // a constant
206
206
  "special",
207
+ "infer",
207
208
 
208
209
  /**
209
210
  * This is used for handle field that its type depends on previous field type, or value
@@ -226,6 +227,7 @@ export type FieldNode = ({
226
227
  | "fixed_bitset"
227
228
  | "byte_array"
228
229
  | "special"
230
+ | "infer"
229
231
  >,
230
232
  } | {
231
233
  type: "not_implemented",
@@ -262,13 +264,32 @@ export type FieldNode = ({
262
264
  } | {
263
265
  type: "special",
264
266
  comment: string,
267
+ } | { // Call a function
268
+ type: "infer",
269
+ args?: (string | number)[] | undefined,
270
+ function: string
265
271
  }) & {
266
272
  skip_able?: boolean | undefined
267
273
  }
268
274
  /** @hidden */
269
275
  export const Field: z.ZodType<FieldNode> = z.union([
270
276
  z.object({
271
- type: SupportTypes.exclude(["prefixed_array", "prefixed_optional", "string", "id_or_x", "array", "switch", "fixed_point", "enum", "not_implemented", "object", "fixed_bitset", "byte_array", "special"]),
277
+ type: SupportTypes.exclude([
278
+ "prefixed_array",
279
+ "prefixed_optional",
280
+ "string",
281
+ "id_or_x",
282
+ "array",
283
+ "switch",
284
+ "fixed_point",
285
+ "enum",
286
+ "not_implemented",
287
+ "object",
288
+ "fixed_bitset",
289
+ "byte_array",
290
+ "special",
291
+ "infer"
292
+ ]),
272
293
  }),
273
294
  z.object({
274
295
  type: z.literal(["not_implemented"]),
@@ -290,7 +311,9 @@ export const Field: z.ZodType<FieldNode> = z.union([
290
311
  length: z.number().optional()
291
312
  }),
292
313
  z.object({
293
- type: z.literal(["id_or_x", "enum", "prefixed_optional"]),
314
+ type: z.literal(["id_or_x",
315
+ "enum",
316
+ "prefixed_optional"]),
294
317
  /**
295
318
  * For case like `Array<subType>` or `PrefixedOptional<subType>`
296
319
  */
@@ -344,9 +367,14 @@ export const Field: z.ZodType<FieldNode> = z.union([
344
367
  length: z.int()
345
368
  }),
346
369
  z.object({
347
- type: z.literal(["special"]),
370
+ type: z.literal("special"),
348
371
  comment: z.string()
349
372
  }),
373
+ z.object({
374
+ type: z.literal("infer"),
375
+ args: z.string().or(z.number()).array().optional(),
376
+ function: z.string(),
377
+ })
350
378
  ])
351
379
  .and(
352
380
  z.object({
@@ -398,7 +426,8 @@ export class PacketRegistry {
398
426
  if (this.loaded) return;
399
427
  this.loaded = true;
400
428
 
401
- const json = getFile(version, "packets") as Record<string, any>;
429
+ const json = getFile(version,
430
+ "packets") as Record<string, any>;
402
431
 
403
432
  const definition = VersionDefinitions.parse(json);
404
433
  for (const [stateKey, state] of Object.entries(definition)) {
@@ -427,7 +456,8 @@ export class PacketRegistry {
427
456
  numbericId = parseInt(id, 16);
428
457
  else numbericId = id;
429
458
  if (isNaN(numbericId))
430
- throw new UnexpectedValue("valid packet id", id.toString(), "name or number or hex");
459
+ throw new UnexpectedValue("valid packet id", id.toString(),
460
+ "name or number or hex");
431
461
  else
432
462
  return this.definition[state][type]["0x" + numbericId.toString(16).toUpperCase()];
433
463
  }
@@ -44,6 +44,10 @@ export class BlockState {
44
44
  if (defaultVal) return defaultVal;
45
45
  return null;
46
46
  }
47
+
48
+ /**
49
+ * Get the block facing
50
+ */
47
51
  public getFacing(): "north" | "south" | "west" | "east" | null { return this.get("facing"); }
48
52
  }
49
53
 
@@ -51,6 +55,9 @@ export class BlockState {
51
55
  * Represent a block
52
56
  */
53
57
  export class Block {
58
+ /**
59
+ * A block will have multiple states (example: a stair will have difference facing).
60
+ */
54
61
  public states: BlockState[];
55
62
 
56
63
  constructor(
@@ -74,16 +81,46 @@ export class Block {
74
81
  if (defaultVal) return defaultVal;
75
82
  return null;
76
83
  }
77
- public getType() { return this.get("type")!; }
84
+
85
+ /**
86
+ * Get the block type.
87
+ *
88
+ * A block type will contain multiple blocks, like type `wall_sign` will have
89
+ * `oak_wall_sign`, `spruce_wall_sign`, `acacia_wall_sign`, etc...
90
+ */
91
+ public getType() { return this.get<string>("type")!; }
92
+ /**
93
+ * Get the block friction.
94
+ *
95
+ * By default, block friction is 0.6, except for ice block family.
96
+ */
78
97
  public getFriction() { return this.get("friction", 0.6); }
98
+ /**
99
+ * Get the block bounciness.
100
+ *
101
+ * By default, block friction is 0, except for slime block.
102
+ */
79
103
  public getBounciness() { return this.get("bounciness", 0); }
104
+ /**
105
+ * Get the block speed factor.
106
+ *
107
+ * By default, block friction is 1, except for soul sand block.
108
+ */
80
109
  public getSpeedFactor() { return this.get("speed_factor", 1); }
110
+ /**
111
+ * Check if the block is climable.
112
+ *
113
+ * By default, block friction is false, except for ladder and vine.
114
+ */
81
115
  public getClimbable() { return this.get("climbable", false); }
116
+ /**
117
+ * Get the block jump factor.
118
+ */
82
119
  public getJumpFactor() { return this.get("jump_factor", 1); }
83
120
  }
84
121
 
85
122
  /**
86
- * Somehow, this is an equivalent implementation of Minecraft `Level`
123
+ * This class is for fetching blocks and chunks data.
87
124
  */
88
125
  export class BlockManager {
89
126
  constructor(private state: SharedState) { }
@@ -115,7 +152,9 @@ export class BlockManager {
115
152
  this.state.checkReady();
116
153
  let { x, y, z } = Vec3.loadArgs(a, b, c);
117
154
  x = Math.floor(x); y = Math.floor(y); z = Math.floor(z);
155
+ // Chunk position
118
156
  const sx = Math.floor(x / 16), sy = Math.floor((y + 64) / 16), sz = Math.floor(z / 16);
157
+ // Block position within the chunk
119
158
  const px = ((x % 16) + 16) % 16, py = ((y % 16) + 16) % 16, pz = ((z % 16) + 16) % 16;
120
159
 
121
160
  if (this.state.cache)
@@ -166,6 +205,13 @@ export class BlockManager {
166
205
  const state = arr.at(this.getLocalPosKey(localPos))!;
167
206
  return this.getBlock(state);
168
207
  }
208
+ /**
209
+ * Delete the chunk cache
210
+ *
211
+ * @param sx chunk x
212
+ * @param sy section y
213
+ * @param sz chunk z
214
+ */
169
215
  public deleteChunkCache(
170
216
  sx: number, sy: number, sz: number,
171
217
  ) {
@@ -193,7 +239,6 @@ export class BlockManager {
193
239
  const stateId = bitsPerEntry <= 8 ? section.palette[localId]! : localId;
194
240
 
195
241
  return BlockRegistry.getState(String(stateId));
196
-
197
242
  }
198
243
  private getLocalPosKey(pos: BaseVec3) {
199
244
  return pos.x + 16 * (pos.y + 16 * pos.z);
@@ -255,8 +300,6 @@ export class BlockGetter {
255
300
  consumer: (context: C, position: BaseVec3) => T,
256
301
  missFactory: (context: C) => T
257
302
  ): T {
258
- let result: T;
259
-
260
303
  if (from.equal(to)) return missFactory(context);
261
304
  const toX = lerp(-Epsilon, to.x, from.x);
262
305
  const toY = lerp(-Epsilon, to.y, from.y);
@@ -281,29 +324,28 @@ export class BlockGetter {
281
324
  let tX = signX === 0 ? Infinity : tDeltaX * (signX > 0 ? 1 - getFrac(fromX) : getFrac(fromX));
282
325
  let tY = signY === 0 ? Infinity : tDeltaY * (signY > 0 ? 1 - getFrac(fromY) : getFrac(fromY));
283
326
  let tZ = signZ === 0 ? Infinity : tDeltaZ * (signZ > 0 ? 1 - getFrac(fromZ) : getFrac(fromZ));
284
- do {
285
- if (tX <= 1.0 || tY <= 1.0 || tZ <= 1.0) {
286
- if (tX < tY) {
287
- if (tX < tZ) {
288
- currentBlockX += signX;
289
- tX += tDeltaX;
290
- } else {
291
- currentBlockZ += signZ;
292
- tZ += tDeltaZ;
293
- }
294
- } else if (tY < tZ) {
295
- currentBlockY += signY;
296
- tY += tDeltaY;
327
+ while (tX <= 1.0 || tY <= 1.0 || tZ <= 1.0) {
328
+ if (tX < tY) {
329
+ if (tX < tZ) {
330
+ currentBlockX += signX;
331
+ tX += tDeltaX;
297
332
  } else {
298
333
  currentBlockZ += signZ;
299
334
  tZ += tDeltaZ;
300
335
  }
301
- result = consumer(context, { x: currentBlockX, y: currentBlockY, z: currentBlockZ });
336
+ } else if (tY < tZ) {
337
+ currentBlockY += signY;
338
+ tY += tDeltaY;
302
339
  } else {
303
- return missFactory(context);
340
+ currentBlockZ += signZ;
341
+ tZ += tDeltaZ;
304
342
  }
305
- } while (result == null);
306
- return result;
343
+ const result = consumer(context, { x: currentBlockX, y: currentBlockY, z: currentBlockZ });
344
+
345
+ if (result !== null)
346
+ return result;
347
+ }
348
+ return missFactory(context);
307
349
  }
308
350
  }
309
351