@vaitosoi/minejs 0.5.1 → 0.6.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 (67) hide show
  1. package/README.md +4 -0
  2. package/assets/minecraft/26.2/components.json +113 -0
  3. package/assets/minecraft/26.2/packets.json +8 -16
  4. package/assets/minecraft/26.3/packets.json +4767 -0
  5. package/assets/minecraft/versionMapping.json +16 -0
  6. package/dist/binary/decoder.d.ts +35 -0
  7. package/dist/binary/decoder.d.ts.map +1 -1
  8. package/dist/binary/decoder.js +665 -2
  9. package/dist/binary/decoder.js.map +1 -1
  10. package/dist/binary/encoder.d.ts +3 -3
  11. package/dist/binary/encoder.d.ts.map +1 -1
  12. package/dist/binary/encoder.js.map +1 -1
  13. package/dist/client/client.d.ts +58 -1
  14. package/dist/client/client.d.ts.map +1 -1
  15. package/dist/client/client.js +38 -0
  16. package/dist/client/client.js.map +1 -1
  17. package/dist/net/tcp.d.ts +6 -2
  18. package/dist/net/tcp.d.ts.map +1 -1
  19. package/dist/net/tcp.js +5 -2
  20. package/dist/net/tcp.js.map +1 -1
  21. package/dist/packet/listener.d.ts +5 -0
  22. package/dist/packet/listener.d.ts.map +1 -1
  23. package/dist/packet/listener.js +78 -5
  24. package/dist/packet/listener.js.map +1 -1
  25. package/dist/packet/sender.d.ts +3 -1
  26. package/dist/packet/sender.d.ts.map +1 -1
  27. package/dist/packet/sender.js +15 -0
  28. package/dist/packet/sender.js.map +1 -1
  29. package/dist/physics/aabb.js +7 -7
  30. package/dist/physics/aabb.js.map +1 -1
  31. package/dist/physics/player.js +1 -5
  32. package/dist/physics/player.js.map +1 -1
  33. package/dist/version/codec.d.ts.map +1 -1
  34. package/dist/version/codec.js +25 -14
  35. package/dist/version/codec.js.map +1 -1
  36. package/dist/version/registry.d.ts +21 -5
  37. package/dist/version/registry.d.ts.map +1 -1
  38. package/dist/version/registry.js +55 -18
  39. package/dist/version/registry.js.map +1 -1
  40. package/dist/world/block.d.ts +10 -8
  41. package/dist/world/block.d.ts.map +1 -1
  42. package/dist/world/block.js +17 -11
  43. package/dist/world/block.js.map +1 -1
  44. package/dist/world/container.d.ts +106 -0
  45. package/dist/world/container.d.ts.map +1 -0
  46. package/dist/world/container.js +240 -0
  47. package/dist/world/container.js.map +1 -0
  48. package/dist/world/state.d.ts +8 -5
  49. package/dist/world/state.d.ts.map +1 -1
  50. package/dist/world/state.js +2 -0
  51. package/dist/world/state.js.map +1 -1
  52. package/package.json +2 -2
  53. package/src/binary/decoder.ts +691 -2
  54. package/src/binary/encoder.ts +3 -3
  55. package/src/client/client.ts +81 -4
  56. package/src/net/tcp.ts +16 -5
  57. package/src/packet/listener.ts +103 -6
  58. package/src/packet/sender.ts +26 -2
  59. package/src/physics/aabb.ts +7 -7
  60. package/src/physics/player.ts +5 -5
  61. package/src/version/codec.ts +24 -14
  62. package/src/version/registry.ts +61 -17
  63. package/src/world/block.ts +19 -17
  64. package/src/world/container.ts +180 -0
  65. package/src/world/state.ts +11 -6
  66. package/test/client/index.ts +49 -21
  67. package/test/client/registry.json +1735 -0
@@ -1,4 +1,4 @@
1
- import { readFile } from "node:fs/promises";
1
+ import { readFileSync } from "node:fs";
2
2
  import { join } from "node:path";
3
3
  import { RegistryItemNotFound, UnexpectedValue, VersionNotSupport } from "../base/error";
4
4
  import { Block, BlockState } from "../world/block";
@@ -7,14 +7,27 @@ import z from "zod";
7
7
  const BASE_REGISTRY_PATH = join(__dirname, "..", "..", "assets", "minecraft");
8
8
  /** @hidden */
9
9
  export const SupportVersions = [
10
- "26.2"
10
+ "26.2",
11
+ "26.3"
11
12
  ];
12
13
 
13
14
  /** @hidden */
14
15
  export const ProtocolVersionMapping: Record<string, number> = {
15
- "26.2": 776
16
+ "26.2": 776,
17
+ "26.3": 777
16
18
  };
17
19
 
20
+ function getFile(version: string, module: string) {
21
+ const map = JSON.parse(readFileSync(join(BASE_REGISTRY_PATH, "versionMapping.json"), "utf-8"));
22
+ if (!(version in map))
23
+ throw new VersionNotSupport(version);
24
+ const versionMap = map[version];
25
+ if (!(module in versionMap))
26
+ throw new VersionNotSupport(version);
27
+ const fileContent = JSON.parse(readFileSync(join(BASE_REGISTRY_PATH, versionMap[module], `${module}.json`), "utf-8"));
28
+ return fileContent;
29
+ }
30
+
18
31
  export class EntityRegistry {
19
32
  private static loaded: boolean = false;
20
33
  public static readonly data: Record<string, { height: number, width: number, type: number }> = {};
@@ -25,14 +38,13 @@ export class EntityRegistry {
25
38
  *
26
39
  * Should be called once time
27
40
  */
28
- public static async load(version: string) {
41
+ public static load(version: string) {
29
42
  if (!SupportVersions.includes(version))
30
43
  throw new VersionNotSupport(version);
31
44
  if (this.loaded) return;
32
45
  this.loaded = true;
33
46
 
34
- const file = await readFile(join(BASE_REGISTRY_PATH, version, "entities.json"), { encoding: "utf8" });
35
- const json = JSON.parse(file);
47
+ const json = getFile(version, "entities");
36
48
  for (const entity in json) {
37
49
  this.data[entity] = json[entity];
38
50
  this.mapTypeToData[json[entity]["id"]] = entity;
@@ -68,14 +80,13 @@ export class BlockRegistry {
68
80
  *
69
81
  * Should be called once time
70
82
  */
71
- public static async load(version: string) {
83
+ public static load(version: string) {
72
84
  if (!SupportVersions.includes(version))
73
85
  throw new VersionNotSupport(version);
74
86
  if (this.loaded) return;
75
87
  this.loaded = true;
76
88
 
77
- const file = await readFile(join(BASE_REGISTRY_PATH, version, "blocks.json"), { encoding: "utf8" });
78
- const json = JSON.parse(file) as Record<string, any>;
89
+ const json = getFile(version, "blocks") as Record<string, any>;
79
90
  for (const [type, blockRaw] of Object.entries(json)) {
80
91
  const block = new Block(type, blockRaw['definition'], blockRaw['properties'], blockRaw['states']);
81
92
  this.blocks[type] = block;
@@ -113,20 +124,44 @@ export class EffectRegistry {
113
124
  *
114
125
  * Should be called once time
115
126
  */
116
- public static async load(version: string) {
127
+ public static load(version: string) {
117
128
  if (!SupportVersions.includes(version))
118
129
  throw new VersionNotSupport(version);
119
130
  if (this.loaded) return;
120
131
  this.loaded = true;
121
132
 
122
- const file = await readFile(join(BASE_REGISTRY_PATH, version, "effects.json"), { encoding: "utf8" });
123
- const json = JSON.parse(file) as Record<string, any>;
133
+ const json = getFile(version, "effects") as Record<string, any>;
124
134
  for (const [name, id] of Object.entries(json)) {
125
135
  this.effects[name] = id;
126
136
  }
127
137
  }
128
138
  }
129
139
 
140
+ export class ComponentTypeRegistry {
141
+ private static loaded: boolean = false;
142
+
143
+ public static readonly components: Record<string, number> = {};
144
+ public static readonly idToName: Record<number, string> = {};
145
+
146
+ /**
147
+ * Load effects registry from JSON file.
148
+ *
149
+ * Should be called once time
150
+ */
151
+ public static load(version: string) {
152
+ if (!SupportVersions.includes(version))
153
+ throw new VersionNotSupport(version);
154
+ if (this.loaded) return;
155
+ this.loaded = true;
156
+
157
+ const json = getFile(version, "components") as Record<string, number>;
158
+ for (const [name, id] of Object.entries(json)) {
159
+ this.components[name] = id;
160
+ this.idToName[id] = name;
161
+ }
162
+ }
163
+ }
164
+
130
165
  /** @hidden */
131
166
  export const SupportTypes = z.enum([
132
167
  "byte",
@@ -166,7 +201,9 @@ export const SupportTypes = z.enum([
166
201
  "bitset",
167
202
  "fixed_bitset",
168
203
  "byte_array",
204
+ "slot",
169
205
  "null", // a constant
206
+ "special",
170
207
 
171
208
  /**
172
209
  * This is used for handle field that its type depends on previous field type, or value
@@ -188,6 +225,7 @@ export type FieldNode = ({
188
225
  | "not_implemented"
189
226
  | "fixed_bitset"
190
227
  | "byte_array"
228
+ | "special"
191
229
  >,
192
230
  } | {
193
231
  type: "not_implemented",
@@ -221,13 +259,16 @@ export type FieldNode = ({
221
259
  } | {
222
260
  type: "fixed_bitset" | "byte_array",
223
261
  length: number,
262
+ } | {
263
+ type: "special",
264
+ comment: string,
224
265
  }) & {
225
266
  skip_able?: boolean | undefined
226
267
  }
227
268
  /** @hidden */
228
269
  export const Field: z.ZodType<FieldNode> = z.union([
229
270
  z.object({
230
- type: SupportTypes.exclude(["prefixed_array", "prefixed_optional", "string", "id_or_x", "array", "switch", "fixed_point", "enum", "not_implemented", "object", "fixed_bitset", "byte_array"]),
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"]),
231
272
  }),
232
273
  z.object({
233
274
  type: z.literal(["not_implemented"]),
@@ -301,7 +342,11 @@ export const Field: z.ZodType<FieldNode> = z.union([
301
342
  // These type require predefined-length
302
343
  type: z.union([z.literal("fixed_bitset"), z.literal("byte_array")]),
303
344
  length: z.int()
304
- })
345
+ }),
346
+ z.object({
347
+ type: z.literal(["special"]),
348
+ comment: z.string()
349
+ }),
305
350
  ])
306
351
  .and(
307
352
  z.object({
@@ -347,14 +392,13 @@ export class PacketRegistry {
347
392
  *
348
393
  * Should be called once time
349
394
  */
350
- public static async load(version: string) {
395
+ public static load(version: string) {
351
396
  if (!SupportVersions.includes(version))
352
397
  throw new VersionNotSupport(version);
353
398
  if (this.loaded) return;
354
399
  this.loaded = true;
355
400
 
356
- const file = await readFile(join(BASE_REGISTRY_PATH, version, "packets.json"), { encoding: "utf8" });
357
- const json = JSON.parse(file) as Record<string, any>;
401
+ const json = getFile(version, "packets") as Record<string, any>;
358
402
 
359
403
  const definition = VersionDefinitions.parse(json);
360
404
  for (const [stateKey, state] of Object.entries(definition)) {
@@ -5,6 +5,15 @@ import { BaseVec3, Direction, Vec3 } from "../physics/direction";
5
5
  import { SharedState } from "./state";
6
6
  import { NotImplemented } from "../base/error";
7
7
 
8
+ export enum BlockFace {
9
+ Bottom = 0,
10
+ Top = 1,
11
+ North = 2,
12
+ South = 3,
13
+ West = 4,
14
+ East = 5,
15
+ }
16
+
8
17
  /**
9
18
  * Represent a state of a block
10
19
  */
@@ -129,13 +138,10 @@ export class BlockManager {
129
138
  const sectionCache = this.state.cache.get(sectionKey);
130
139
  if (sectionCache) {
131
140
  const cachedState = sectionCache.at(this.getLocalPosKey(localPos));
132
- if (cachedState) {
133
- console.log("cache hit", sectionKey, localPos);
141
+ if (cachedState)
134
142
  return this.getBlock(cachedState);
135
- }
136
143
  }
137
144
 
138
- console.log("cache miss", sectionKey, localPos);
139
145
  const section = this.state.world!.chunks[`${this.state.player!.dimension}:${sx}:${sz}`]?.sections[sy]?.block;
140
146
  if (!section) return null;
141
147
  if (section.data === null) return BlockRegistry.getState(section.palette[0]!.toString())!;
@@ -219,11 +225,6 @@ export class BlockManager {
219
225
  }
220
226
  }
221
227
 
222
- interface Context {
223
- getBlockState: (position: BaseVec3) => VoxelShape,
224
- from: Vec3,
225
- to: Vec3
226
- }
227
228
 
228
229
  /**
229
230
  * For clipping math
@@ -231,9 +232,9 @@ interface Context {
231
232
  * @hidden
232
233
  */
233
234
  export class BlockGetter {
234
- public static clip(from: Vec3, to: Vec3, context: Context) {
235
+ public static clip(from: Vec3, to: Vec3, getBlockState: (position: BaseVec3) => VoxelShape) {
235
236
  return this.traverseBlocks(
236
- from, to, context,
237
+ from, to, { getBlockState, from, to },
237
238
  (context, pos) => {
238
239
  const blockState = context.getBlockState(pos);
239
240
  const { from, to } = context;
@@ -247,12 +248,13 @@ export class BlockGetter {
247
248
  );
248
249
  }
249
250
 
250
- public static traverseBlocks<T, C = Context>(
251
+ public static traverseBlocks<T, C>(
251
252
  from: Vec3,
252
253
  to: Vec3,
253
254
  context: C,
254
255
  consumer: (context: C, position: BaseVec3) => T,
255
- missFactory: (context: C) => T): T {
256
+ missFactory: (context: C) => T
257
+ ): T {
256
258
  let result: T;
257
259
 
258
260
  if (from.equal(to)) return missFactory(context);
@@ -276,9 +278,9 @@ export class BlockGetter {
276
278
  const tDeltaX = signX == 0 ? Infinity : signX / dx;
277
279
  const tDeltaY = signY == 0 ? Infinity : signY / dy;
278
280
  const tDeltaZ = signZ == 0 ? Infinity : signZ / dz;
279
- let tX = tDeltaX * (signX > 0 ? 1 - getFrac(fromX) : getFrac(fromX));
280
- let tY = tDeltaY * (signY > 0 ? 1 - getFrac(fromY) : getFrac(fromY));
281
- let tZ = tDeltaZ * (signZ > 0 ? 1 - getFrac(fromZ) : getFrac(fromZ));
281
+ let tX = signX === 0 ? Infinity : tDeltaX * (signX > 0 ? 1 - getFrac(fromX) : getFrac(fromX));
282
+ let tY = signY === 0 ? Infinity : tDeltaY * (signY > 0 ? 1 - getFrac(fromY) : getFrac(fromY));
283
+ let tZ = signZ === 0 ? Infinity : tDeltaZ * (signZ > 0 ? 1 - getFrac(fromZ) : getFrac(fromZ));
282
284
  do {
283
285
  if (tX <= 1.0 || tY <= 1.0 || tZ <= 1.0) {
284
286
  if (tX < tY) {
@@ -319,7 +321,7 @@ export class BlockHitResult {
319
321
  ) { }
320
322
 
321
323
  public static hit(location: Vec3, direction: Direction, pos: BaseVec3) {
322
- return new BlockHitResult(true, location, direction, pos);
324
+ return new BlockHitResult(false, location, direction, pos);
323
325
  }
324
326
 
325
327
  public static miss(location: Vec3, direction: Direction, pos: BaseVec3) {
@@ -0,0 +1,180 @@
1
+ import { TextComponent } from "../base/typing";
2
+
3
+ /**
4
+ * Represent the data of a slot
5
+ *
6
+ * @see https://minecraft.wiki/w/Java_Edition_protocol/Slot_data#Format
7
+ */
8
+ export interface Slot {
9
+ counts: number,
10
+ itemId: number | undefined,
11
+ addComponents: Record<string, any> | undefined,
12
+ removeComponents: number[] | undefined
13
+ }
14
+
15
+ /**
16
+ * Represent a container (such as inventory, chest, anvil, ...)
17
+ */
18
+ export class Container {
19
+ /**
20
+ * State ID
21
+ *
22
+ * You SHOULD NOT edit this field since this field is for syncing state from client and server
23
+ */
24
+ public stateId: number = 0;
25
+ /**
26
+ * Slots data
27
+ *
28
+ * @see https://minecraft.wiki/w/Java_Edition_protocol/Inventory For more info how how slot are organized
29
+ */
30
+ public slots: Slot[] = [];
31
+ /**
32
+ * Data from Set Container Property packet
33
+ *
34
+ * @see https://minecraft.wiki/w/Java_Edition_protocol/Packets#Set_Container_Property
35
+ *
36
+ * | Field | Meaning |
37
+ * |------------------------------------------|---------|
38
+ * | # **Furnace / Blast furnace / Smoker** | ------- |
39
+ * | fuel_left | counting from fuel burn time down to 0 |
40
+ * | max_burn_time | fuel burn time or 0 (in-game ticks) |
41
+ * | progress_arrow | counting from 0 to maximum progress (in-game ticks) |
42
+ * | max_progress | always 200 on the vanilla server |
43
+ * | # **Enchantment table** | ------- |
44
+ * | level_requirement_for_top_enchantment | |
45
+ * | level_requirement_for_middle_enchantment | The enchantment's xp level requirement |
46
+ * | level_requirement_for_bottom_enchantment | |
47
+ * | enchantment_seed | Used for drawing the enchantment names (in SGA) clientside. The same seed is used to calculate enchantments, but some of the data isn't sent to the client to prevent easily guessing the entire list (the seed value here is the regular seed bitwise and 0xFFFFFFF0). |
48
+ * | enchant_id_of_top_enchantment | |
49
+ * | enchant_id_of_middle_enchantment | The enchantment ID (set to -1 to hide it), see below for values |
50
+ * | enchant_id_of_bottom_enchantment | |
51
+ * | enchant_level_of_top_enchantment | |
52
+ * | enchant_level_of_middle_enchantment | The enchantment level (1 = I, 2 = II, 6 = VI, etc.), or -1 if no enchant |
53
+ * | enchant_level_of_bottom_enchantment | |
54
+ * | # **Beacon** | ------- |
55
+ * | power_level | 0-4, controls what effect buttons are enabled |
56
+ * | first_effect | Potion effect ID for the first effect, or -1 if no effect |
57
+ * | second_level | Potion effect ID for the second effect, or -1 if no effect |
58
+ * | # **Anvil** | ------- |
59
+ * | repair_cost | The repair's cost in XP levels |
60
+ * | # **Brewing stand** | ------- |
61
+ * | brew_time | 0 – 400, with 400 making the arrow empty, and 0 making the arrow full |
62
+ * | fuel_time | 0 - 20, with 0 making the arrow empty, and 20 making the arrow full |
63
+ * | # **Stonecutter** | ------- |
64
+ * | selected_recipe | The index of the selected recipe. -1 means none is selected |
65
+ * | # **Loom** | ------- |
66
+ * | selected_pattern | The index of the selected pattern. 0 means none is selected, 0 is also the internal ID of the "base" pattern |
67
+ * | # **Lectern** | ------- |
68
+ * | page_number | The current page number, starting from 0. |
69
+ * | # **Smithing table** | ------- |
70
+ * | has_recipe_error | True if greater than zero |
71
+ * | # **Crafter** | ------- |
72
+ * | slot_0_disabled | |
73
+ * | slot_1_disabled | |
74
+ * | slot_2_disabled | |
75
+ * | slot_3_disabled | |
76
+ * | slot_4_disabled | 0 If the slot is enabled, 1 if the slot is disabled |
77
+ * | slot_5_disabled | |
78
+ * | slot_6_disabled | |
79
+ * | slot_7_disabled | |
80
+ * | slot_8_disabled | |
81
+ *
82
+ * @see https://minecraft.wiki/w/Java_Edition_data_values#Effects For effect ID
83
+ */
84
+ public properties: Record<string, number> = {};
85
+
86
+ constructor(
87
+ /**
88
+ * This is not used at the moment
89
+ */
90
+ public id: number,
91
+ /**
92
+ * @see https://minecraft.wiki/w/Java_Edition_protocol/Inventory#Types
93
+ */
94
+ public type: number,
95
+ public rawTitle: TextComponent
96
+ ) { }
97
+
98
+ /**
99
+ * @see https://minecraft.wiki/w/Java_Edition_protocol/Packets#Set_Container_Property
100
+ */
101
+ public setProperty(property: number, data: number) {
102
+ switch (this.type) {
103
+ case 14: // Furnace
104
+ case 10: // Blast furnace
105
+ case 22: // Smoker
106
+ switch (property) {
107
+ case 0: this.properties["fuel_left"] = data; break;
108
+ case 1: this.properties["max_burn_time"] = data; break;
109
+ case 2: this.properties["progress_arrow"] = data; break;
110
+ case 3: this.properties["max_progress"] = data; break;
111
+ }
112
+ break;
113
+ case 13: // Enchantment table
114
+ switch (property) {
115
+ case 0: this.properties["level_requirement_for_top_enchantment"] = data; break;
116
+ case 1: this.properties["level_requirement_for_middle_enchantment"] = data; break;
117
+ case 2: this.properties["level_requirement_for_bottom_enchantment"] = data; break;
118
+ case 3: this.properties["enchantment_seed"] = data; break;
119
+ case 4: this.properties["enchant_id_of_top_enchantment"] = data; break;
120
+ case 5: this.properties["enchant_id_of_middle_enchantment"] = data; break;
121
+ case 6: this.properties["enchant_id_of_bottom_enchantment"] = data; break;
122
+ case 7: this.properties["enchant_level_of_top_enchantment"] = data; break;
123
+ case 8: this.properties["enchant_level_of_middle_enchantment"] = data; break;
124
+ case 9: this.properties["enchant_level_of_bottom_enchantment"] = data; break;
125
+ }
126
+ break;
127
+ case 9: // Beacon
128
+ switch (property) {
129
+ case 0: this.properties["power_level"] = data; break;
130
+ case 1: this.properties["first_effect"] = data; break;
131
+ case 2: this.properties["second_level"] = data; break;
132
+ }
133
+ break;
134
+ case 8: // Anvil
135
+ switch (property) {
136
+ case 0: this.properties["repair_cost"] = data; break;
137
+ }
138
+ break;
139
+ case 11: // Brewing stand
140
+ switch (property) {
141
+ case 0: this.properties["brew_time"] = data; break;
142
+ case 1: this.properties["fuel_time"] = data; break;
143
+ }
144
+ break;
145
+ case 24: // Stonecutter
146
+ switch (property) {
147
+ case 0: this.properties["selected_recipe"] = data; break;
148
+ }
149
+ break;
150
+ case 18: // Loom
151
+ switch (property) {
152
+ case 0: this.properties["selected_pattern"] = data; break;
153
+ }
154
+ break;
155
+ case 17: // Lectern
156
+ switch (property) {
157
+ case 0: this.properties["page_number"] = data; break;
158
+ }
159
+ break;
160
+ case 21: // Smithing table
161
+ switch (property) {
162
+ case 0: this.properties["has_recipe_error"] = data; break;
163
+ }
164
+ break;
165
+ case 7: // Crafter
166
+ switch (property) {
167
+ case 0: this.properties["slot_0_disabled"] = data; break;
168
+ case 1: this.properties["slot_1_disabled"] = data; break;
169
+ case 2: this.properties["slot_2_disabled"] = data; break;
170
+ case 3: this.properties["slot_3_disabled"] = data; break;
171
+ case 4: this.properties["slot_4_disabled"] = data; break;
172
+ case 5: this.properties["slot_5_disabled"] = data; break;
173
+ case 6: this.properties["slot_6_disabled"] = data; break;
174
+ case 7: this.properties["slot_7_disabled"] = data; break;
175
+ case 8: this.properties["slot_8_disabled"] = data; break;
176
+ }
177
+ break;
178
+ }
179
+ }
180
+ }
@@ -1,5 +1,4 @@
1
1
  import { Cipheriv, Decipheriv } from "node:crypto";
2
- import { If } from "../base/typing";
3
2
  import { Angle, BaseVec3 } from "../physics/direction";
4
3
  import { AuthRelatedNotFound, ClientNotReady } from "../base/error";
5
4
  import { ClientEvents, ClientOption } from "../client/client";
@@ -7,6 +6,7 @@ import { AuthClient } from "../client/auth";
7
6
  import { MessageLink } from "../message/link";
8
7
  import { SignatureCache } from "../message/sigCache";
9
8
  import { CacheImplementation, LRUCache } from "../base/cache";
9
+ import { Container, Slot } from "./container";
10
10
 
11
11
  export interface Server {
12
12
  knownPacks?: ServerKnownPack
@@ -125,7 +125,10 @@ export interface ClientPlayer {
125
125
  /** Current dimension */
126
126
  dimension: string,
127
127
 
128
- effects: Record<number, Effect>
128
+ effects: Record<number, Effect>,
129
+
130
+ inventory: Container,
131
+ carryingItem: Slot | undefined,
129
132
  }
130
133
 
131
134
  export enum ClientStatus {
@@ -160,7 +163,7 @@ export type SendingPacket = {
160
163
  /**
161
164
  * For managing shared data between classes
162
165
  */
163
- export class SharedState<IsReady extends boolean = boolean> {
166
+ export class SharedState {
164
167
  private mutationQueue: MutateState[] = [];
165
168
  private eventQueue: EmittedEvent[] = [];
166
169
  private packetQueue: SendingPacket[] = [];
@@ -186,9 +189,10 @@ export class SharedState<IsReady extends boolean = boolean> {
186
189
 
187
190
  public server: Server | undefined = undefined;
188
191
  public registry: Record<string, ServerRegistryEntry[]> | undefined = undefined;
189
- public world: If<IsReady, ServerWorld> = null as any;
190
- public player: If<IsReady, ClientPlayer> = null as any;
192
+ public world: ServerWorld | null = null;
193
+ public player: ClientPlayer | null = null;
191
194
  public messageCount: number = 0;
195
+ public openingContainer: Container | undefined = undefined;
192
196
 
193
197
  public cache: CacheImplementation<Uint16Array> | undefined = undefined;
194
198
 
@@ -211,7 +215,7 @@ export class SharedState<IsReady extends boolean = boolean> {
211
215
  }
212
216
  }
213
217
 
214
- public isReady(): this is SharedState<true> {
218
+ public isReady() {
215
219
  return this.status === ClientStatus.Ready;
216
220
  }
217
221
 
@@ -246,6 +250,7 @@ export class SharedState<IsReady extends boolean = boolean> {
246
250
  this.world = undefined as any;
247
251
  this.player = undefined as any;
248
252
  this.messageCount = 0;
253
+ this.openingContainer = undefined as any;
249
254
 
250
255
  if (this.clientOptions.shouldVerifyMessageSignature)
251
256
  this.messageSignatureCache = SignatureCache.default();
@@ -1,13 +1,22 @@
1
- import { Input, Client } from "../../src/index";
1
+ import { Input, Client, ClientEvents } from "../../src/index";
2
2
 
3
3
  const client = new Client({
4
4
  playerName: "bot",
5
5
  host: "localhost",
6
6
  port: 25565,
7
7
  version: "26.2",
8
- // debug: {
9
- // packetLogger: true
10
- // },
8
+ debug: {
9
+ packetLogger: true,
10
+ ignorePackets: [
11
+ "move_entity_pos", "move_entity_pos_rot", "move_entity_rot",
12
+ "set_entity_motion", "rotate_head", "set_time",
13
+ "add_entity", "remove_entities", "bundle_delimiter",
14
+ "entity_position_sync", "update_attributes",
15
+ "move_player_pos", "move_player_pos_rot", "move_player_rot",
16
+ "player_chat", "keep_alive", "entity_event", "tab_list"
17
+ ],
18
+ ignoreTCPPacketLogs: [0, 83, 54, 101, 1, 99, 53, 35, 131, 113, 102, 44, 56, 65, 34, 77, 122]
19
+ },
11
20
  loadRegistry: false,
12
21
  // auth: {
13
22
  // client_id: "d86254d8-edf7-4640-90eb-643c99af188e",
@@ -17,23 +26,30 @@ const client = new Client({
17
26
  // },
18
27
  // shouldVerifyMessageOrder: true,
19
28
  // shouldVerifyMessageSignature: true
20
- loadAndCacheChunk: true
29
+ loadAndCacheChunk: false
21
30
  });
31
+ const forwardEventToConsole = <K extends keyof ClientEvents>(name: K) => client.on(name, ((...args: any[]) => console.dir({ name, args }, { depth: null })) as any);
22
32
  client.connect();
23
- client.on("disconnect", (...args) => console.dir({ name: "disconnect", args }, { depth: null }));
24
- client.on("disconnectRaw", (...args) => console.dir({ name: "disconnectRaw", args }, { depth: null }));
25
- // client.on("loadChunk", (...args) => console.dir({ name: "loadChunk", args }, { depth: null }));
26
- // client.on("unloadChunk", (...args) => console.dir({ name: "unloadChunk", args }, { depth: null }));
27
- // client.on("spawnEntity", (...args) => console.dir({ name: "spawnEntity", args }, { depth: null }));
28
- // client.on("updateEntity", (...args) => console.dir({ name: "updateEntity", args }, { depth: null }));
29
- // client.on("removeEntity", (...args) => console.dir({ name: "removeEntity", args }, { depth: null }));
30
- client.on("playerPosition", (...args) => console.dir({ name: "playerPosition", args }, { depth: null }));
31
- client.on("message", (...args) => console.dir({ name: "message", args }, { depth: null }));
32
- client.on("systemMessage", (...args) => console.dir({ name: "systemMessage", args }, { depth: null }));
33
- client.on("systemMessageRaw", (...args) => console.dir({ name: "systemMessageRaw", args }, { depth: null }));
34
- client.on("actionBar", (...args) => console.dir({ name: "actionBar", args }, { depth: null }));
35
- client.on("actionBarRaw", (...args) => console.dir({ name: "actionBarRaw", args }, { depth: null }));
36
- client.on("message", (message) => {
33
+ forwardEventToConsole("disconnect");
34
+ forwardEventToConsole("disconnectRaw");
35
+ // forwardEventToConsole("loadChunk");
36
+ // forwardEventToConsole("unloadChunk");
37
+ // forwardEventToConsole("spawnEntity");
38
+ // forwardEventToConsole("updateEntity");
39
+ // forwardEventToConsole("removeEntity");
40
+ // forwardEventToConsole("playerPosition");
41
+ // forwardEventToConsole("message");
42
+ forwardEventToConsole("systemMessage");
43
+ forwardEventToConsole("systemMessageRaw");
44
+ forwardEventToConsole("actionBar");
45
+ forwardEventToConsole("actionBarRaw");
46
+ forwardEventToConsole("openContainer");
47
+ forwardEventToConsole("closeContainer");
48
+ forwardEventToConsole("containerContent");
49
+ forwardEventToConsole("containerProperty");
50
+ forwardEventToConsole("tablist");
51
+
52
+ client.on("message", async (message) => {
37
53
  if (!message.content.startsWith("_")) return;
38
54
  const args = message.content.slice(1).split(" ");
39
55
  switch (args[0]) {
@@ -59,8 +75,20 @@ client.on("message", (message) => {
59
75
  const [, x, y, z] = args.map(val => parseInt(val)) as [any, number, number, number];
60
76
  console.time("get_block");
61
77
  const state = client.at(x, y, z);
62
- console.timeEnd("get_block");
63
- console.log(state);
78
+ console.timeEnd("get_block");
79
+ if (state) {
80
+ console.dir(state);
81
+ client.chat(state!.owner.type);
82
+ } else
83
+ client.chat("no block");
84
+ break;
85
+ }
86
+
87
+ case "open": {
88
+ const [, x, y, z] = args.map(val => parseInt(val)) as [any, number, number, number];
89
+ const success = client.openBlock(x, y, z);
90
+ if (success) client.chat("opening");
91
+ else client.chat("failed");
64
92
  break;
65
93
  }
66
94