@vaitosoi/minejs 0.5.0 → 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 (109) 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/base/bitset.d.ts.map +1 -1
  7. package/dist/base/bitset.js.map +1 -1
  8. package/dist/base/buffer.d.ts +1 -0
  9. package/dist/base/buffer.d.ts.map +1 -1
  10. package/dist/base/buffer.js +1 -0
  11. package/dist/base/buffer.js.map +1 -1
  12. package/dist/base/http.d.ts +1 -0
  13. package/dist/base/http.d.ts.map +1 -1
  14. package/dist/base/http.js +1 -0
  15. package/dist/base/http.js.map +1 -1
  16. package/dist/base/math.d.ts +2 -0
  17. package/dist/base/math.d.ts.map +1 -1
  18. package/dist/base/math.js +2 -0
  19. package/dist/base/math.js.map +1 -1
  20. package/dist/base/typing.d.ts +5 -0
  21. package/dist/base/typing.d.ts.map +1 -1
  22. package/dist/binary/decoder.d.ts +39 -0
  23. package/dist/binary/decoder.d.ts.map +1 -1
  24. package/dist/binary/decoder.js +669 -2
  25. package/dist/binary/decoder.js.map +1 -1
  26. package/dist/binary/encoder.d.ts +7 -3
  27. package/dist/binary/encoder.d.ts.map +1 -1
  28. package/dist/binary/encoder.js +4 -0
  29. package/dist/binary/encoder.js.map +1 -1
  30. package/dist/client/client.d.ts +58 -1
  31. package/dist/client/client.d.ts.map +1 -1
  32. package/dist/client/client.js +38 -0
  33. package/dist/client/client.js.map +1 -1
  34. package/dist/message/link.d.ts +3 -0
  35. package/dist/message/link.d.ts.map +1 -1
  36. package/dist/message/link.js +3 -0
  37. package/dist/message/link.js.map +1 -1
  38. package/dist/message/sigCache.d.ts +5 -0
  39. package/dist/message/sigCache.d.ts.map +1 -1
  40. package/dist/message/sigCache.js +5 -0
  41. package/dist/message/sigCache.js.map +1 -1
  42. package/dist/net/tcp.d.ts +7 -3
  43. package/dist/net/tcp.d.ts.map +1 -1
  44. package/dist/net/tcp.js +6 -3
  45. package/dist/net/tcp.js.map +1 -1
  46. package/dist/packet/listener.d.ts +8 -0
  47. package/dist/packet/listener.d.ts.map +1 -1
  48. package/dist/packet/listener.js +81 -5
  49. package/dist/packet/listener.js.map +1 -1
  50. package/dist/packet/sender.d.ts +6 -1
  51. package/dist/packet/sender.d.ts.map +1 -1
  52. package/dist/packet/sender.js +18 -0
  53. package/dist/packet/sender.js.map +1 -1
  54. package/dist/physics/aabb.d.ts +3 -0
  55. package/dist/physics/aabb.d.ts.map +1 -1
  56. package/dist/physics/aabb.js +10 -7
  57. package/dist/physics/aabb.js.map +1 -1
  58. package/dist/physics/direction.d.ts +3 -0
  59. package/dist/physics/direction.d.ts.map +1 -1
  60. package/dist/physics/direction.js +3 -0
  61. package/dist/physics/direction.js.map +1 -1
  62. package/dist/physics/player.d.ts +3 -0
  63. package/dist/physics/player.d.ts.map +1 -1
  64. package/dist/physics/player.js +4 -5
  65. package/dist/physics/player.js.map +1 -1
  66. package/dist/version/codec.d.ts +4 -0
  67. package/dist/version/codec.d.ts.map +1 -1
  68. package/dist/version/codec.js +29 -14
  69. package/dist/version/codec.js.map +1 -1
  70. package/dist/version/registry.d.ts +30 -6
  71. package/dist/version/registry.d.ts.map +1 -1
  72. package/dist/version/registry.js +64 -19
  73. package/dist/version/registry.js.map +1 -1
  74. package/dist/world/block.d.ts +10 -8
  75. package/dist/world/block.d.ts.map +1 -1
  76. package/dist/world/block.js +17 -11
  77. package/dist/world/block.js.map +1 -1
  78. package/dist/world/container.d.ts +106 -0
  79. package/dist/world/container.d.ts.map +1 -0
  80. package/dist/world/container.js +240 -0
  81. package/dist/world/container.js.map +1 -0
  82. package/dist/world/state.d.ts +11 -5
  83. package/dist/world/state.d.ts.map +1 -1
  84. package/dist/world/state.js +5 -0
  85. package/dist/world/state.js.map +1 -1
  86. package/package.json +2 -2
  87. package/src/base/bitset.ts +0 -1
  88. package/src/base/buffer.ts +1 -0
  89. package/src/base/http.ts +1 -0
  90. package/src/base/math.ts +2 -0
  91. package/src/base/typing.ts +6 -0
  92. package/src/binary/decoder.ts +695 -2
  93. package/src/binary/encoder.ts +7 -3
  94. package/src/client/client.ts +81 -4
  95. package/src/message/link.ts +3 -0
  96. package/src/message/sigCache.ts +5 -0
  97. package/src/net/tcp.ts +17 -10
  98. package/src/packet/listener.ts +106 -6
  99. package/src/packet/sender.ts +29 -2
  100. package/src/physics/aabb.ts +10 -7
  101. package/src/physics/direction.ts +3 -0
  102. package/src/physics/player.ts +8 -5
  103. package/src/version/codec.ts +29 -14
  104. package/src/version/registry.ts +71 -18
  105. package/src/world/block.ts +19 -17
  106. package/src/world/container.ts +180 -0
  107. package/src/world/state.ts +14 -6
  108. package/test/client/index.ts +49 -21
  109. package/test/client/registry.json +1735 -0
@@ -1,18 +1,33 @@
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";
5
5
  import z from "zod";
6
6
 
7
- export const BASE_REGISTRY_PATH = join(__dirname, "..", "..", "assets", "minecraft");
7
+ const BASE_REGISTRY_PATH = join(__dirname, "..", "..", "assets", "minecraft");
8
+ /** @hidden */
8
9
  export const SupportVersions = [
9
- "26.2"
10
+ "26.2",
11
+ "26.3"
10
12
  ];
11
13
 
14
+ /** @hidden */
12
15
  export const ProtocolVersionMapping: Record<string, number> = {
13
- "26.2": 776
16
+ "26.2": 776,
17
+ "26.3": 777
14
18
  };
15
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
+
16
31
  export class EntityRegistry {
17
32
  private static loaded: boolean = false;
18
33
  public static readonly data: Record<string, { height: number, width: number, type: number }> = {};
@@ -23,14 +38,13 @@ export class EntityRegistry {
23
38
  *
24
39
  * Should be called once time
25
40
  */
26
- public static async load(version: string) {
41
+ public static load(version: string) {
27
42
  if (!SupportVersions.includes(version))
28
43
  throw new VersionNotSupport(version);
29
44
  if (this.loaded) return;
30
45
  this.loaded = true;
31
46
 
32
- const file = await readFile(join(BASE_REGISTRY_PATH, version, "entities.json"), { encoding: "utf8" });
33
- const json = JSON.parse(file);
47
+ const json = getFile(version, "entities");
34
48
  for (const entity in json) {
35
49
  this.data[entity] = json[entity];
36
50
  this.mapTypeToData[json[entity]["id"]] = entity;
@@ -66,14 +80,13 @@ export class BlockRegistry {
66
80
  *
67
81
  * Should be called once time
68
82
  */
69
- public static async load(version: string) {
83
+ public static load(version: string) {
70
84
  if (!SupportVersions.includes(version))
71
85
  throw new VersionNotSupport(version);
72
86
  if (this.loaded) return;
73
87
  this.loaded = true;
74
88
 
75
- const file = await readFile(join(BASE_REGISTRY_PATH, version, "blocks.json"), { encoding: "utf8" });
76
- const json = JSON.parse(file) as Record<string, any>;
89
+ const json = getFile(version, "blocks") as Record<string, any>;
77
90
  for (const [type, blockRaw] of Object.entries(json)) {
78
91
  const block = new Block(type, blockRaw['definition'], blockRaw['properties'], blockRaw['states']);
79
92
  this.blocks[type] = block;
@@ -111,20 +124,45 @@ export class EffectRegistry {
111
124
  *
112
125
  * Should be called once time
113
126
  */
114
- public static async load(version: string) {
127
+ public static load(version: string) {
115
128
  if (!SupportVersions.includes(version))
116
129
  throw new VersionNotSupport(version);
117
130
  if (this.loaded) return;
118
131
  this.loaded = true;
119
132
 
120
- const file = await readFile(join(BASE_REGISTRY_PATH, version, "effects.json"), { encoding: "utf8" });
121
- const json = JSON.parse(file) as Record<string, any>;
133
+ const json = getFile(version, "effects") as Record<string, any>;
122
134
  for (const [name, id] of Object.entries(json)) {
123
135
  this.effects[name] = id;
124
136
  }
125
137
  }
126
138
  }
127
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
+
165
+ /** @hidden */
128
166
  export const SupportTypes = z.enum([
129
167
  "byte",
130
168
  "unsigned_byte",
@@ -163,13 +201,16 @@ export const SupportTypes = z.enum([
163
201
  "bitset",
164
202
  "fixed_bitset",
165
203
  "byte_array",
204
+ "slot",
166
205
  "null", // a constant
206
+ "special",
167
207
 
168
208
  /**
169
209
  * This is used for handle field that its type depends on previous field type, or value
170
210
  */
171
211
  "switch"
172
212
  ]);
213
+ /** @hidden */
173
214
  export type FieldNode = ({
174
215
  type: Exclude<z.infer<typeof SupportTypes>,
175
216
  | "prefixed_array"
@@ -184,6 +225,7 @@ export type FieldNode = ({
184
225
  | "not_implemented"
185
226
  | "fixed_bitset"
186
227
  | "byte_array"
228
+ | "special"
187
229
  >,
188
230
  } | {
189
231
  type: "not_implemented",
@@ -217,12 +259,16 @@ export type FieldNode = ({
217
259
  } | {
218
260
  type: "fixed_bitset" | "byte_array",
219
261
  length: number,
262
+ } | {
263
+ type: "special",
264
+ comment: string,
220
265
  }) & {
221
266
  skip_able?: boolean | undefined
222
267
  }
268
+ /** @hidden */
223
269
  export const Field: z.ZodType<FieldNode> = z.union([
224
270
  z.object({
225
- 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"]),
226
272
  }),
227
273
  z.object({
228
274
  type: z.literal(["not_implemented"]),
@@ -296,24 +342,32 @@ export const Field: z.ZodType<FieldNode> = z.union([
296
342
  // These type require predefined-length
297
343
  type: z.union([z.literal("fixed_bitset"), z.literal("byte_array")]),
298
344
  length: z.int()
299
- })
345
+ }),
346
+ z.object({
347
+ type: z.literal(["special"]),
348
+ comment: z.string()
349
+ }),
300
350
  ])
301
351
  .and(
302
352
  z.object({
303
353
  skip_able: z.boolean().optional()
304
354
  })
305
355
  );
356
+ /** @hidden */
306
357
  export const PacketObject = z.object({
307
358
  name: z.string(),
308
359
  id: z.number(),
309
360
  structure: z.record(z.string(), Field),
310
361
  skipForNow: z.boolean().default(false)
311
362
  });
363
+ /** @hidden */
312
364
  export const PacketsDefinition = z.record(z.string().or(z.number()), PacketObject);
365
+ /** @hidden */
313
366
  export const StatesDefinition = z.object({
314
367
  clientbound: PacketsDefinition,
315
368
  serverbound: PacketsDefinition,
316
369
  });
370
+ /** @hidden */
317
371
  export const VersionDefinitions = z.object({
318
372
  handshaking: StatesDefinition,
319
373
  status: StatesDefinition,
@@ -338,14 +392,13 @@ export class PacketRegistry {
338
392
  *
339
393
  * Should be called once time
340
394
  */
341
- public static async load(version: string) {
395
+ public static load(version: string) {
342
396
  if (!SupportVersions.includes(version))
343
397
  throw new VersionNotSupport(version);
344
398
  if (this.loaded) return;
345
399
  this.loaded = true;
346
400
 
347
- const file = await readFile(join(BASE_REGISTRY_PATH, version, "packets.json"), { encoding: "utf8" });
348
- const json = JSON.parse(file) as Record<string, any>;
401
+ const json = getFile(version, "packets") as Record<string, any>;
349
402
 
350
403
  const definition = VersionDefinitions.parse(json);
351
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 {
@@ -157,7 +160,10 @@ export type SendingPacket = {
157
160
  data: Record<string, any>
158
161
  }
159
162
 
160
- export class SharedState<IsReady extends boolean = boolean> {
163
+ /**
164
+ * For managing shared data between classes
165
+ */
166
+ export class SharedState {
161
167
  private mutationQueue: MutateState[] = [];
162
168
  private eventQueue: EmittedEvent[] = [];
163
169
  private packetQueue: SendingPacket[] = [];
@@ -183,9 +189,10 @@ export class SharedState<IsReady extends boolean = boolean> {
183
189
 
184
190
  public server: Server | undefined = undefined;
185
191
  public registry: Record<string, ServerRegistryEntry[]> | undefined = undefined;
186
- public world: If<IsReady, ServerWorld> = null as any;
187
- public player: If<IsReady, ClientPlayer> = null as any;
192
+ public world: ServerWorld | null = null;
193
+ public player: ClientPlayer | null = null;
188
194
  public messageCount: number = 0;
195
+ public openingContainer: Container | undefined = undefined;
189
196
 
190
197
  public cache: CacheImplementation<Uint16Array> | undefined = undefined;
191
198
 
@@ -208,7 +215,7 @@ export class SharedState<IsReady extends boolean = boolean> {
208
215
  }
209
216
  }
210
217
 
211
- public isReady(): this is SharedState<true> {
218
+ public isReady() {
212
219
  return this.status === ClientStatus.Ready;
213
220
  }
214
221
 
@@ -243,6 +250,7 @@ export class SharedState<IsReady extends boolean = boolean> {
243
250
  this.world = undefined as any;
244
251
  this.player = undefined as any;
245
252
  this.messageCount = 0;
253
+ this.openingContainer = undefined as any;
246
254
 
247
255
  if (this.clientOptions.shouldVerifyMessageSignature)
248
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