@block_factory/lib 0.0.6 → 0.0.9

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 (72) hide show
  1. package/_module/BlockFactory.ts +10 -19
  2. package/_module/util/Command.ts +1 -9
  3. package/_module/util/Forms/Form.ts +5 -31
  4. package/_module/util/Forms/FormAction.ts +2 -1
  5. package/_module/util/Forms/FormMessage.ts +2 -1
  6. package/_module/util/Forms/FormModal.ts +9 -10
  7. package/_module/util/Forms/FormRegistry.ts +20 -23
  8. package/_module/util/Forms/IForm.ts +31 -0
  9. package/_module/util/Globals.ts +26 -0
  10. package/_module/util/ISystem.ts +58 -0
  11. package/_module/util/IVector.ts +420 -0
  12. package/_module/util/Math.ts +2 -0
  13. package/_module/util/Navigation.ts +130 -0
  14. package/_module/util/TempLeaker.ts +137 -0
  15. package/_module/util/Wrapper/IEntity.ts +93 -25
  16. package/_module/util/Wrapper/IItemStack.ts +63 -0
  17. package/_module/util/Wrapper/IPlayer.ts +85 -29
  18. package/_module/util/Wrapper/_Common.ts +128 -0
  19. package/_module/util/Wrapper/{Container.ts → _Container.ts} +5 -5
  20. package/index.js +3941 -791
  21. package/package.json +9 -5
  22. package/_module/DataTypes.ts +0 -10
  23. package/_module/Framework/EntityTasks.ts +0 -164
  24. package/_module/Framework/ItemTasks.ts +0 -157
  25. package/_module/Framework/PlayerTasks.ts +0 -125
  26. package/_module/Framework/Threads.ts +0 -72
  27. package/_module/util/System.ts +0 -21
  28. package/_module/util/Vector.ts +0 -388
  29. package/_types/_module/BlockFactory.d.ts +0 -19
  30. package/_types/_module/BlockFactory.d.ts.map +0 -1
  31. package/_types/_module/DataTypes.d.ts +0 -10
  32. package/_types/_module/DataTypes.d.ts.map +0 -1
  33. package/_types/_module/Framework/EntityTasks.d.ts +0 -37
  34. package/_types/_module/Framework/EntityTasks.d.ts.map +0 -1
  35. package/_types/_module/Framework/ItemTasks.d.ts +0 -59
  36. package/_types/_module/Framework/ItemTasks.d.ts.map +0 -1
  37. package/_types/_module/Framework/PlayerTasks.d.ts +0 -28
  38. package/_types/_module/Framework/PlayerTasks.d.ts.map +0 -1
  39. package/_types/_module/Framework/Threads.d.ts +0 -22
  40. package/_types/_module/Framework/Threads.d.ts.map +0 -1
  41. package/_types/_module/Types.d.ts +0 -10
  42. package/_types/_module/Types.d.ts.map +0 -1
  43. package/_types/_module/util/Command.d.ts +0 -92
  44. package/_types/_module/util/Command.d.ts.map +0 -1
  45. package/_types/_module/util/Forms/Form.d.ts +0 -12
  46. package/_types/_module/util/Forms/Form.d.ts.map +0 -1
  47. package/_types/_module/util/Forms/FormAction.d.ts +0 -73
  48. package/_types/_module/util/Forms/FormAction.d.ts.map +0 -1
  49. package/_types/_module/util/Forms/FormMessage.d.ts +0 -24
  50. package/_types/_module/util/Forms/FormMessage.d.ts.map +0 -1
  51. package/_types/_module/util/Forms/FormModal.d.ts +0 -66
  52. package/_types/_module/util/Forms/FormModal.d.ts.map +0 -1
  53. package/_types/_module/util/Forms/FormRegistry.d.ts +0 -12
  54. package/_types/_module/util/Forms/FormRegistry.d.ts.map +0 -1
  55. package/_types/_module/util/Math.d.ts +0 -20
  56. package/_types/_module/util/Math.d.ts.map +0 -1
  57. package/_types/_module/util/RawText.d.ts +0 -60
  58. package/_types/_module/util/RawText.d.ts.map +0 -1
  59. package/_types/_module/util/Signal.d.ts +0 -70
  60. package/_types/_module/util/Signal.d.ts.map +0 -1
  61. package/_types/_module/util/System.d.ts +0 -4
  62. package/_types/_module/util/System.d.ts.map +0 -1
  63. package/_types/_module/util/Vector.d.ts +0 -212
  64. package/_types/_module/util/Vector.d.ts.map +0 -1
  65. package/_types/_module/util/Wrapper/Container.d.ts +0 -9
  66. package/_types/_module/util/Wrapper/Container.d.ts.map +0 -1
  67. package/_types/_module/util/Wrapper/IEntity.d.ts +0 -12
  68. package/_types/_module/util/Wrapper/IEntity.d.ts.map +0 -1
  69. package/_types/_module/util/Wrapper/IPlayer.d.ts +0 -13
  70. package/_types/_module/util/Wrapper/IPlayer.d.ts.map +0 -1
  71. package/_types/index.d.ts +0 -3
  72. package/_types/index.d.ts.map +0 -1
@@ -0,0 +1,420 @@
1
+ /*
2
+ **************************************************
3
+ Copyright (c) Block Factory - All rights reserved.
4
+ **************************************************
5
+ Author: Donthedev <https://github.com/voxeldon>
6
+ **************************************************
7
+ */
8
+
9
+ /**
10
+ * 2D vector utility class.
11
+ * Provides common vector math operations for 2D space.
12
+ */
13
+ export class IVector2 {
14
+
15
+ /** Constant zero vector (0, 0) */
16
+ static ZERO: IVector2 = new IVector2(0, 0);
17
+
18
+ /** Up direction (0, 1) */
19
+ static UP: IVector2 = new IVector2(0, 1);
20
+
21
+ /** Down direction (0, -1) */
22
+ static DOWN: IVector2 = new IVector2(0, -1);
23
+
24
+ /** Left direction (-1, 0) */
25
+ static LEFT: IVector2 = new IVector2(-1, 0);
26
+
27
+ /** Right direction (1, 0) */
28
+ static RIGHT: IVector2 = new IVector2(1, 0);
29
+
30
+ /**
31
+ * Creates a new IVector2.
32
+ * @param x X component
33
+ * @param y Y component
34
+ */
35
+ constructor(public x: number, public y: number) { }
36
+
37
+ /**
38
+ * Adds a vector or scalar to a vector.
39
+ * @param a Base vector
40
+ * @param b Vector or scalar to add
41
+ */
42
+ static add(a: IVector2, b: IVector2 | number): IVector2 {
43
+ if (typeof b === 'number') return new IVector2(a.x + b, a.y + b);
44
+ else return new IVector2(a.x + b.x, a.y + b.y);
45
+ }
46
+
47
+ /**
48
+ * Subtracts a vector or scalar from a vector.
49
+ * @param a Base vector
50
+ * @param b Vector or scalar to subtract
51
+ */
52
+ static subtract(a: IVector2, b: IVector2 | number): IVector2 {
53
+ if (typeof b === 'number') return new IVector2(a.x - b, a.y - b);
54
+ else return new IVector2(a.x - b.x, a.y - b.y);
55
+ }
56
+
57
+ /**
58
+ * Multiplies a vector by another vector (component-wise) or scalar.
59
+ */
60
+ static multiply(a: IVector2, b: IVector2 | number): IVector2 {
61
+ if (typeof b === 'number') return new IVector2(a.x * b, a.y * b);
62
+ else return new IVector2(a.x * b.x, a.y * b.y);
63
+ }
64
+
65
+ /**
66
+ * Divides a vector by another vector (component-wise) or scalar.
67
+ */
68
+ static divide(a: IVector2, b: IVector2 | number): IVector2 {
69
+ if (typeof b === 'number') return new IVector2(a.x / b, a.y / b);
70
+ else return new IVector2(a.x / b.x, a.y / b.y);
71
+ }
72
+
73
+ /**
74
+ * Linearly interpolates between two vectors.
75
+ * @param t Interpolation factor (0–1)
76
+ */
77
+ static lerp(a: IVector2, b: IVector2, t: number): IVector2 {
78
+ return new IVector2(
79
+ a.x + (b.x - a.x) * t,
80
+ a.y + (b.y - a.y) * t
81
+ );
82
+ }
83
+
84
+ /**
85
+ * Clamps a vector between a minimum and maximum vector.
86
+ */
87
+ static clamp(v: IVector2, min: IVector2, max: IVector2): IVector2 {
88
+ return new IVector2(
89
+ Math.min(Math.max(v.x, min.x), max.x),
90
+ Math.min(Math.max(v.y, min.y), max.y)
91
+ );
92
+ }
93
+
94
+ /**
95
+ * Dot product of two vectors.
96
+ */
97
+ static dot(a: IVector2, b: IVector2): number {
98
+ return a.x * b.x + a.y * b.y;
99
+ }
100
+
101
+ /**
102
+ * Length (magnitude) of a vector.
103
+ */
104
+ static magnitude(a: IVector2): number {
105
+ return Math.sqrt(a.x * a.x + a.y * a.y);
106
+ }
107
+
108
+ /**
109
+ * Returns a normalized (unit length) vector.
110
+ * If magnitude is zero, returns (0, 0).
111
+ */
112
+ static normalize(a: IVector2): IVector2 {
113
+ const mag = IVector2.magnitude(a);
114
+ return mag === 0 ? new IVector2(0, 0) : new IVector2(a.x / mag, a.y / mag);
115
+ }
116
+
117
+ /**
118
+ * Distance between two vectors.
119
+ */
120
+ static distance(a: IVector2, b: IVector2): number {
121
+ return IVector2.magnitude(IVector2.subtract(a, b));
122
+ }
123
+
124
+ /**
125
+ * Returns the negated vector.
126
+ */
127
+ static negate(a: IVector2): IVector2 {
128
+ return new IVector2(-a.x, -a.y);
129
+ }
130
+
131
+ /**
132
+ * Checks exact equality between two vectors.
133
+ */
134
+ static equals(a: IVector2, b: IVector2): boolean {
135
+ return a.x === b.x && a.y === b.y;
136
+ }
137
+
138
+ /**
139
+ * Checks approximate equality between two vectors.
140
+ * @param epsilon Allowed difference threshold
141
+ */
142
+ static approxEquals(a: IVector2, b: IVector2, epsilon = 0.0001): boolean {
143
+ return (
144
+ Math.abs(a.x - b.x) < epsilon &&
145
+ Math.abs(a.y - b.y) < epsilon
146
+ );
147
+ }
148
+
149
+ /**
150
+ * Returns the angle (in radians) between two vectors.
151
+ * Returns 0 if either vector has zero length.
152
+ */
153
+ static angle(a: IVector2, b: IVector2): number {
154
+ const magA = IVector2.magnitude(a);
155
+ const magB = IVector2.magnitude(b);
156
+ const denom = magA * magB;
157
+ if (denom === 0) return 0;
158
+
159
+ let c = IVector2.dot(a, b) / denom;
160
+ c = Math.max(-1, Math.min(1, c));
161
+ return Math.acos(c);
162
+ }
163
+
164
+ /**
165
+ * Returns a perpendicular vector (-y, x).
166
+ */
167
+ static perpendicular(a: IVector2): IVector2 {
168
+ return new IVector2(-a.y, a.x);
169
+ }
170
+
171
+ /**
172
+ * Floors each vector paramater.
173
+ */
174
+ static floor(v: IVector2): IVector2 {
175
+ return new IVector2(Math.floor(v.x), Math.floor(v.y));
176
+ }
177
+
178
+ /**
179
+ * Return vector as a string
180
+ * @param format Returns string with x: y: z: format.
181
+ */
182
+ static toString(v: IVector2, format = false): string {
183
+ if (format) return `x:${v.x} y:${v.y}`;
184
+ return `${v.x} ${v.y}`;
185
+ }
186
+ }
187
+
188
+ /**
189
+ * 3D vector utility class.
190
+ * Provides common vector math operations for 3D space.
191
+ */
192
+ export class IVector3 {
193
+
194
+ /** Constant zero vector (0, 0, 0) */
195
+ static ZERO: IVector3 = new IVector3(0, 0, 0);
196
+
197
+ /** Up direction (0, 1, 0) */
198
+ static UP: IVector3 = new IVector3(0, 1, 0);
199
+
200
+ /** Down direction (0, -1, 0) */
201
+ static DOWN: IVector3 = new IVector3(0, -1, 0);
202
+
203
+ /** Left direction (-1, 0, 0) */
204
+ static LEFT: IVector3 = new IVector3(-1, 0, 0);
205
+
206
+ /** Right direction (1, 0, 0) */
207
+ static RIGHT: IVector3 = new IVector3(1, 0, 0);
208
+
209
+ /** Forward direction (0, 0, 1) */
210
+ static FORWARD: IVector3 = new IVector3(0, 0, 1);
211
+
212
+ /** Backward direction (0, 0, -1) */
213
+ static BACK: IVector3 = new IVector3(0, 0, -1);
214
+
215
+ /** West direction (-1, 0, 0) */
216
+ static WEST: IVector3 = new IVector3(-1, 0, 0);
217
+
218
+ /** East direction (1, 0, 0) */
219
+ static EAST: IVector3 = new IVector3(1, 0, 0);
220
+
221
+ /** North direction (0, 0, 1) */
222
+ static NORTH: IVector3 = new IVector3(0, 0, 1);
223
+
224
+ /** South direction (0, 0, -1) */
225
+ static SOUTH: IVector3 = new IVector3(0, 0, -1);
226
+
227
+ /**
228
+ * Creates a new IVector3.
229
+ * @param x X component
230
+ * @param y Y component
231
+ * @param z Z component
232
+ */
233
+ constructor(public x: number, public y: number, public z: number) { }
234
+
235
+ /**
236
+ * Adds a vector or scalar to a vector.
237
+ * @param a Base vector
238
+ * @param b Vector or scalar to add
239
+ */
240
+ static add(a: IVector3, b: IVector3 | number): IVector3 {
241
+ if (typeof b === 'number') return new IVector3(a.x + b, a.y + b, a.z + b);
242
+ else return new IVector3(a.x + b.x, a.y + b.y, a.z + b.z);
243
+ }
244
+
245
+ /**
246
+ * Subtracts a vector or scalar from a vector.
247
+ * @param a Base vector
248
+ * @param b Vector or scalar to subtract
249
+ */
250
+ static subtract(a: IVector3, b: IVector3 | number): IVector3 {
251
+ if (typeof b === 'number') return new IVector3(a.x - b, a.y - b, a.z - b);
252
+ else return new IVector3(a.x - b.x, a.y - b.y, a.z - b.z);
253
+ }
254
+
255
+ /**
256
+ * Multiplies a vector by another vector (component-wise) or scalar.
257
+ */
258
+ static multiply(a: IVector3, b: IVector3 | number): IVector3 {
259
+ if (typeof b === 'number') return new IVector3(a.x * b, a.y * b, a.z * b);
260
+ else return new IVector3(a.x * b.x, a.y * b.y, a.z * b.z);
261
+ }
262
+
263
+ /**
264
+ * Divides a vector by another vector (component-wise) or scalar.
265
+ */
266
+ static divide(a: IVector3, b: IVector3 | number): IVector3 {
267
+ if (typeof b === 'number') return new IVector3(a.x / b, a.y / b, a.z / b);
268
+ else return new IVector3(a.x / b.x, a.y / b.y, a.z / b.z);
269
+ }
270
+
271
+ /**
272
+ * Linearly interpolates between two vectors.
273
+ * @param t Interpolation factor (0–1)
274
+ */
275
+ static lerp(a: IVector3, b: IVector3, t: number): IVector3 {
276
+ return new IVector3(
277
+ a.x + (b.x - a.x) * t,
278
+ a.y + (b.y - a.y) * t,
279
+ a.z + (b.z - a.z) * t
280
+ );
281
+ }
282
+
283
+ /**
284
+ * Clamps a vector between a minimum and maximum vector.
285
+ */
286
+ static clamp(v: IVector3, min: IVector3, max: IVector3): IVector3 {
287
+ return new IVector3(
288
+ Math.min(Math.max(v.x, min.x), max.x),
289
+ Math.min(Math.max(v.y, min.y), max.y),
290
+ Math.min(Math.max(v.z, min.z), max.z)
291
+ );
292
+ }
293
+
294
+ /**
295
+ * Dot product of two vectors.
296
+ */
297
+ static dot(a: IVector3, b: IVector3): number {
298
+ return a.x * b.x + a.y * b.y + a.z * b.z;
299
+ }
300
+
301
+ /**
302
+ * Cross product of two vectors.
303
+ * Returns a vector perpendicular to both inputs.
304
+ */
305
+ static cross(a: IVector3, b: IVector3): IVector3 {
306
+ return new IVector3(
307
+ a.y * b.z - a.z * b.y,
308
+ a.z * b.x - a.x * b.z,
309
+ a.x * b.y - a.y * b.x
310
+ );
311
+ }
312
+
313
+ /**
314
+ * Length (magnitude) of a vector.
315
+ */
316
+ static magnitude(a: IVector3): number {
317
+ return Math.sqrt(a.x * a.x + a.y * a.y + a.z * a.z);
318
+ }
319
+
320
+ /**
321
+ * Returns a normalized (unit length) vector.
322
+ * If magnitude is zero, returns (0, 0, 0).
323
+ */
324
+ static normalize(a: IVector3): IVector3 {
325
+ const mag = IVector3.magnitude(a);
326
+ return mag === 0
327
+ ? new IVector3(0, 0, 0)
328
+ : new IVector3(a.x / mag, a.y / mag, a.z / mag);
329
+ }
330
+
331
+ /**
332
+ * Distance between two vectors.
333
+ */
334
+ static distance(a: IVector3, b: IVector3): number {
335
+ return IVector3.magnitude(IVector3.subtract(a, b));
336
+ }
337
+
338
+ /**
339
+ * Returns the negated vector.
340
+ */
341
+ static negate(a: IVector3): IVector3 {
342
+ return new IVector3(-a.x, -a.y, -a.z);
343
+ }
344
+
345
+ /**
346
+ * Checks exact equality between two vectors.
347
+ */
348
+ static equals(a: IVector3, b: IVector3): boolean {
349
+ return a.x === b.x && a.y === b.y && a.z === b.z;
350
+ }
351
+
352
+ /**
353
+ * Checks approximate equality between two vectors.
354
+ * @param epsilon Allowed difference threshold
355
+ */
356
+ static approxEquals(a: IVector3, b: IVector3, epsilon = 0.0001): boolean {
357
+ return (
358
+ Math.abs(a.x - b.x) < epsilon &&
359
+ Math.abs(a.y - b.y) < epsilon &&
360
+ Math.abs(a.z - b.z) < epsilon
361
+ );
362
+ }
363
+
364
+ /**
365
+ * Returns the angle (in radians) between two vectors.
366
+ * Returns 0 if either vector has zero length.
367
+ */
368
+ static angle(a: IVector3, b: IVector3): number {
369
+ const magA = IVector3.magnitude(a);
370
+ const magB = IVector3.magnitude(b);
371
+ const denom = magA * magB;
372
+ if (denom === 0) return 0;
373
+
374
+ let c = IVector3.dot(a, b) / denom;
375
+ c = Math.max(-1, Math.min(1, c));
376
+ return Math.acos(c);
377
+ }
378
+
379
+ /**
380
+ * Projects vector `a` onto vector `onto`.
381
+ * If `onto` has zero length, returns (0, 0, 0).
382
+ */
383
+ static project(a: IVector3, onto: IVector3): IVector3 {
384
+ const denom = IVector3.dot(onto, onto);
385
+ if (denom === 0) return new IVector3(0, 0, 0);
386
+
387
+ const scale = IVector3.dot(a, onto) / denom;
388
+ return IVector3.multiply(onto, scale);
389
+ }
390
+
391
+ /**
392
+ * Converts spherical coordinates to cartesian coordinates.
393
+ * @param radius Distance from origin
394
+ * @param theta Azimuth angle (radians)
395
+ * @param phi Polar angle (radians)
396
+ */
397
+ static cartesian(radius: number, theta: number, phi: number): IVector3 {
398
+ return new IVector3(
399
+ radius * Math.sin(phi) * Math.cos(theta),
400
+ radius * Math.sin(phi) * Math.sin(theta),
401
+ radius * Math.cos(phi)
402
+ );
403
+ }
404
+
405
+ /**
406
+ * Floors each vector paramater.
407
+ */
408
+ static floor(v: IVector3): IVector3 {
409
+ return new IVector3(Math.floor(v.x), Math.floor(v.y), Math.floor(v.z));
410
+ }
411
+
412
+ /**
413
+ * Return vector as a string
414
+ * @param format Returns string with x: y: z: format.
415
+ */
416
+ static toString(v: IVector3, format = false): string {
417
+ if (format) return `x:${v.x} y:${v.y} z:${v.z}`;
418
+ return `${v.x} ${v.y} ${v.z}`;
419
+ }
420
+ }
@@ -21,6 +21,7 @@ export namespace MathUtils {
21
21
  return radians * (180 / Math.PI);
22
22
  };
23
23
 
24
+ /** Converts a Minecraft-style rotation (pitch/yaw in degrees) into a unit direction vector. */
24
25
  export function fromRotation(rotation: Vector2): Vector3 {
25
26
  const rotationH = toRadians(rotation.y * -1);
26
27
  const z0 = Math.cos(rotationH);
@@ -37,6 +38,7 @@ export namespace MathUtils {
37
38
  };
38
39
  };
39
40
 
41
+ /** Rotates a local-space offset around the Y axis by a yaw angle (degrees)*/
40
42
  export function rotateOffset(offset: Vector3, yawDegrees: number): Vector3 {
41
43
  const yaw = -yawDegrees * Math.PI / 180;
42
44
  const cos = Math.cos(yaw);
@@ -0,0 +1,130 @@
1
+ import { Block, Entity, system, TicksPerSecond } from "@minecraft/server";
2
+ import { Signal } from "./Signal";
3
+ import { IVector3 } from "./IVector";
4
+ import { ICustomEntity, IEntity } from "../BlockFactory";
5
+
6
+ export type OnNavPointReachedEvent<T extends ICustomEntity = ICustomEntity> = {
7
+ entity: IEntity<T>;
8
+ targetLocation: IVector3;
9
+ originLocation: IVector3;
10
+ };
11
+
12
+ export type OnNavigatingEntityStuckEvent<T extends ICustomEntity = ICustomEntity> = {
13
+ entity: IEntity<T>;
14
+ targetLocation: IVector3;
15
+ originLocation: IVector3;
16
+ };
17
+
18
+ const MAX_NAV_INSTS: number = 2;
19
+ const NAV_CYCLE_TAG_ID: string = "e547e9b28165";
20
+
21
+ export class Navigation<T extends ICustomEntity = ICustomEntity> {
22
+ public static onNavPointReachedEvent = new Signal<OnNavPointReachedEvent>();
23
+ public static onNavigatingEntityStuck = new Signal<OnNavigatingEntityStuckEvent>();
24
+ private source: IEntity<T>;
25
+ private targetId: string;
26
+ private static instanceIndex = new Map<string, number>();
27
+ private instanceId: number | undefined;
28
+ private typeId: string;
29
+ private intervalId: number = -1;
30
+ private navTarget: Entity | undefined
31
+ private originLocation: IVector3 = IVector3.ZERO;
32
+
33
+
34
+ public constructor(source: IEntity<T>, targetId: string) {
35
+ this.source = source;
36
+ this.targetId = targetId;
37
+ this.typeId = source.typeId;
38
+ }
39
+ private obstructionFix(location: IVector3): IVector3 {
40
+ let block: Block | undefined = this.source.dimension.getBlock(location);
41
+ if (block === undefined) throw new Error("obstructionFix error");
42
+ if (block.isAir) return location;
43
+ const ray = this.source.dimension.getBlockFromRay(new IVector3(location.x, 300, location.z), IVector3.DOWN);
44
+ if (!ray?.block) throw new Error("obstructionFix raycast error");
45
+ return new IVector3(ray.block.x, ray.block.y +1, ray.block.z);
46
+
47
+ }
48
+
49
+ public async setNavPoint(location: IVector3): Promise<void> {
50
+ console.warn(`Trying to set nav point @${IVector3.toString(IVector3.floor(location))}`);
51
+ if (!this.source || !this.source.dimension) throw Error("Critical source error");
52
+ if (this.instanceId !== undefined) {
53
+ return;
54
+ }
55
+ const i: number = Navigation.instanceIndex.get(this.source.typeId) || 0;
56
+ this.instanceId = i;
57
+ if (i === MAX_NAV_INSTS) {
58
+ console.warn(`Max navigation instances exeded. | Tried: ${i} - Max: ${MAX_NAV_INSTS}`);
59
+ return;
60
+ };
61
+ Navigation.instanceIndex.set(this.source.typeId, i + 1);
62
+ location = this.obstructionFix(location);
63
+ const target: Entity = this.source.dimension.spawnEntity(this.targetId, location);
64
+ this.navTarget = target;
65
+ const startDist: number = IVector3.distance(this.source.location, target.location);
66
+ if (startDist > 64) {
67
+ this.clearNavPoint();
68
+ return;
69
+ }
70
+ await system.waitTicks(1);
71
+ const tagId: string = `${NAV_CYCLE_TAG_ID}_${this.instanceId}`;
72
+ target.addTag(tagId);
73
+ this.source.addTag(tagId);
74
+ this.source.isNavigating = true;
75
+ this.processNavCycle(target, location);
76
+ this.originLocation = this.source.location;
77
+
78
+ }
79
+
80
+ private processNavCycle(target: Entity, location: IVector3): void {
81
+ let cycles = 0;
82
+ const maxCycles: number = 10;
83
+
84
+ const intervalId: number = system.runInterval(() => {
85
+ try {
86
+ if (!this.source.isValid || !target.isValid) {
87
+ this.clearNavPoint();
88
+ return;
89
+ }
90
+ const v = this.source.getVelocity();
91
+ const horizSpeed = Math.hypot(v.x, v.z);
92
+
93
+ if (horizSpeed < 0.05) {
94
+ cycles++;
95
+
96
+ if (cycles >= maxCycles) {
97
+ Navigation.onNavigatingEntityStuck.emit({ entity: this.source, targetLocation: location, originLocation: this.originLocation })
98
+ this.clearNavPoint();
99
+ return;
100
+ }
101
+ } else cycles = 0;
102
+
103
+ const distance = IVector3.distance(this.source.location, target.location);
104
+ if (distance > 2) return;
105
+
106
+ Navigation.onNavPointReachedEvent.emit({ entity: this.source, targetLocation: location, originLocation: this.originLocation });
107
+ this.clearNavPoint();
108
+ } catch (e) {
109
+ console.warn(e);
110
+ this.clearNavPoint();
111
+ }
112
+ }, TicksPerSecond / 4);
113
+ this.intervalId = intervalId;
114
+ }
115
+
116
+ public clearNavPoint(): void {
117
+ if (this.intervalId === -1 || !this.navTarget) return;
118
+ this.instanceId = undefined;
119
+ const i: number = Navigation.instanceIndex.get(this.typeId) || 0;
120
+ if (i > 0) Navigation.instanceIndex.set(this.typeId, i - 1);
121
+ if (this.source.isValid) {
122
+ this.source.isNavigating = false;
123
+ this.source.removeTag(`${NAV_CYCLE_TAG_ID}_${this.instanceId}`);
124
+ }
125
+ if (this.navTarget.isValid) this.navTarget.remove();
126
+ system.clearRun(this.intervalId);
127
+ this.intervalId = -1;
128
+ this.navTarget = undefined;
129
+ }
130
+ }
@@ -0,0 +1,137 @@
1
+ import { Entity, Player, system } from "@minecraft/server";
2
+
3
+ /**
4
+ * Relay utility that abuses `playAnimation(... stopExpression ...)`
5
+ * to write values into Molang temps (`t.*`) on the client.
6
+ *
7
+ * - Always includes `t.source_name` and `t.__nonce__`
8
+ * - Values are serialized into a single `stopExpression` string
9
+ * - Intended for lightweight HUD / animation-controller syncing
10
+ *
11
+ * @external @example
12
+ *
13
+ * Client json relay example
14
+ *
15
+ * "scripts": {
16
+ * "initialize": [
17
+ * "v._nonce_swing = -1;",
18
+ * "v.swing = 0;"
19
+ * ],
20
+ * "pre_animation": [
21
+ * "q.is_name_any(t.source_name??'') && (t.__nonce__??-1) != v._nonce_swing ? { v._nonce_swing = t.__nonce__??-1; v.swing = (t.swing??0); };"
22
+ * ]
23
+ * }
24
+ */
25
+ export class TempLeak {
26
+ private static readonly ANIM = "5bb1702b_252a_4133_8aff_8ed11f168e4e";
27
+ private static readonly CTRL = "2ca2eabb_c7d9_4777_8497_57444ea2cd50";
28
+
29
+ private static nonceBySource = new Map<string, number>();
30
+
31
+ private static nextNonce(source: Player | Entity): number {
32
+ const n = (this.nonceBySource.get(source.id) ?? 0) + 1;
33
+ this.nonceBySource.set(source.id, n);
34
+ return n;
35
+ }
36
+
37
+ private static esc(str: string): string {
38
+ return str.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
39
+ }
40
+
41
+ private static fmt(value: unknown): string {
42
+ if (typeof value === "number") return Number.isFinite(value) ? String(value) : "0";
43
+ if (typeof value === "boolean") return value ? "1" : "0";
44
+ if (typeof value === "string") return `'${this.esc(value)}'`;
45
+ return `'${this.esc(String(value))}'`;
46
+ }
47
+
48
+ private static isPlayer(e: Player | Entity): e is Player {
49
+ return e instanceof Player;
50
+ }
51
+
52
+ private static buildStopExp(
53
+ source: Player | Entity,
54
+ nonce: number,
55
+ fields: Record<string, unknown>
56
+ ): string {
57
+ const sourceName = this.isPlayer(source) ? source.name : source.typeId;
58
+
59
+ let exp =
60
+ `t.source_name='${this.esc(sourceName)}';` +
61
+ `t.__nonce__=${nonce};`;
62
+
63
+ for (const [k, v] of Object.entries(fields)) {
64
+ const key = k.includes(".") ? k : `t.${k}`;
65
+ exp += `${key}=${this.fmt(v)};`;
66
+ }
67
+
68
+ exp += "return 0;";
69
+ return exp;
70
+ }
71
+
72
+ /**
73
+ * Sends a “no-op” update that only bumps `t.__nonce__` (and sets `t.source_name`).
74
+ *
75
+ *
76
+ * @param source Target source to receive the update.
77
+ */
78
+ public static refresh(source: Player | Entity): void {
79
+ TempLeak.send(source, {});
80
+ }
81
+
82
+ /**
83
+ * Emits a single payload update to the client by playing a hidden animation
84
+ * whose `stopExpression` assigns values into `t.*`.
85
+ *
86
+ * Notes:
87
+ * - A per-source monotonic nonce is included as `t.__nonce__`.
88
+ * - Keys in `fields` are written as `t.<key>` unless you pass a dotted path
89
+ * (e.g. `"t.swing"` or `"t.ui.swing"`).
90
+ * - Numbers are clamped to finite values, booleans become `1/0`, and strings
91
+ * are escaped.
92
+ *
93
+ * @param source Target source to receive the update.
94
+ * @param fields Key/value pairs to assign into `t.*` on the client.
95
+ */
96
+ public static send(source: Player | Entity, fields: Record<string, unknown>): void {
97
+ const nonce = this.nextNonce(source);
98
+ source.playAnimation(this.ANIM, {
99
+ controller: this.CTRL,
100
+ stopExpression: this.buildStopExp(source, nonce, fields),
101
+ });
102
+ }
103
+
104
+ /**
105
+ * Convenience helper for impulse leaks.
106
+ *
107
+ * This sends `setFields` immediately, then (optionally) sends `clearFields`
108
+ * after `clearDelayTicks`.
109
+ *
110
+ * If `clearFields` is provided, it is used as-is.
111
+ *
112
+ * Intended use:
113
+ * - Fire-and-forget booleans like `t.swing = 1` then clear back to `0`
114
+ * - Short pulses for UI triggers where the client watches for nonce changes
115
+ *
116
+ * @param source Target source to receive the update(s).
117
+ * @param setFields Fields to set immediately.
118
+ * @param clearFields Fields to send after the delay (optional).
119
+ * @param clearDelayTicks Tick delay before sending `clearFields` (default: 1).
120
+ */
121
+ public static pulse(source: Player | Entity,setFields: Record<string, unknown>,clearFields?: Record<string, unknown>,clearDelayTicks: number = 1): void {
122
+ this.send(source, setFields);
123
+ if (!clearFields) return;
124
+ system.runTimeout(() => {
125
+ const autoClear: Record<string, unknown> = {};
126
+ if (!clearFields) {
127
+ for (const [k, v] of Object.entries(setFields)) {
128
+ if (typeof v === "string") autoClear[k] = "";
129
+ else autoClear[k] = 0;
130
+ }
131
+ clearFields = autoClear;
132
+ }
133
+
134
+ this.send(source, clearFields);
135
+ }, clearDelayTicks);
136
+ }
137
+ }