@block_factory/lib 0.0.5 → 0.0.8
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.
- package/_module/BlockFactory.ts +10 -20
- package/_module/util/Command.ts +1 -9
- package/_module/util/Forms/Form.ts +5 -31
- package/_module/util/Forms/FormAction.ts +2 -1
- package/_module/util/Forms/FormMessage.ts +2 -1
- package/_module/util/Forms/FormModal.ts +9 -10
- package/_module/util/Forms/FormRegistry.ts +20 -23
- package/_module/util/Forms/IForm.ts +31 -0
- package/_module/util/Globals.ts +26 -0
- package/_module/util/ISystem.ts +58 -0
- package/_module/util/IVector.ts +420 -0
- package/_module/util/Math.ts +2 -0
- package/_module/util/Navigation.ts +130 -0
- package/_module/util/Signal.ts +71 -7
- package/_module/util/TempLeaker.ts +137 -0
- package/_module/util/Wrapper/IEntity.ts +93 -25
- package/_module/util/Wrapper/IItemStack.ts +63 -0
- package/_module/util/Wrapper/IPlayer.ts +73 -29
- package/_module/util/Wrapper/_Common.ts +130 -0
- package/_module/util/Wrapper/{Container.ts → _Container.ts} +5 -5
- package/index.js +3911 -521
- package/package.json +10 -4
- package/typedoc.json +6 -0
- package/_module/Framework/EntityTasks.ts +0 -203
- package/_module/Framework/Threads.ts +0 -72
- package/_module/Framework/_INIT.ts +0 -39
- package/_module/Types.ts +0 -10
- package/_module/util/System.ts +0 -21
- package/_module/util/Vector.ts +0 -388
- package/_types/_module/BlockFactory.d.ts +0 -19
- package/_types/_module/BlockFactory.d.ts.map +0 -1
- package/_types/_module/Framework/EntityTasks.d.ts +0 -40
- package/_types/_module/Framework/EntityTasks.d.ts.map +0 -1
- package/_types/_module/Framework/Threads.d.ts +0 -22
- package/_types/_module/Framework/Threads.d.ts.map +0 -1
- package/_types/_module/Framework/_INIT.d.ts +0 -19
- package/_types/_module/Framework/_INIT.d.ts.map +0 -1
- package/_types/_module/Types.d.ts +0 -10
- package/_types/_module/Types.d.ts.map +0 -1
- package/_types/_module/util/Command.d.ts +0 -92
- package/_types/_module/util/Command.d.ts.map +0 -1
- package/_types/_module/util/Forms/Form.d.ts +0 -12
- package/_types/_module/util/Forms/Form.d.ts.map +0 -1
- package/_types/_module/util/Forms/FormAction.d.ts +0 -73
- package/_types/_module/util/Forms/FormAction.d.ts.map +0 -1
- package/_types/_module/util/Forms/FormMessage.d.ts +0 -24
- package/_types/_module/util/Forms/FormMessage.d.ts.map +0 -1
- package/_types/_module/util/Forms/FormModal.d.ts +0 -66
- package/_types/_module/util/Forms/FormModal.d.ts.map +0 -1
- package/_types/_module/util/Forms/FormRegistry.d.ts +0 -12
- package/_types/_module/util/Forms/FormRegistry.d.ts.map +0 -1
- package/_types/_module/util/Math.d.ts +0 -20
- package/_types/_module/util/Math.d.ts.map +0 -1
- package/_types/_module/util/RawText.d.ts +0 -60
- package/_types/_module/util/RawText.d.ts.map +0 -1
- package/_types/_module/util/Signal.d.ts +0 -11
- package/_types/_module/util/Signal.d.ts.map +0 -1
- package/_types/_module/util/System.d.ts +0 -4
- package/_types/_module/util/System.d.ts.map +0 -1
- package/_types/_module/util/Vector.d.ts +0 -212
- package/_types/_module/util/Vector.d.ts.map +0 -1
- package/_types/_module/util/Wrapper/Container.d.ts +0 -9
- package/_types/_module/util/Wrapper/Container.d.ts.map +0 -1
- package/_types/_module/util/Wrapper/IEntity.d.ts +0 -12
- package/_types/_module/util/Wrapper/IEntity.d.ts.map +0 -1
- package/_types/_module/util/Wrapper/IPlayer.d.ts +0 -13
- package/_types/_module/util/Wrapper/IPlayer.d.ts.map +0 -1
- package/_types/index.d.ts +0 -3
- 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
|
+
}
|
package/_module/util/Math.ts
CHANGED
|
@@ -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
|
+
}
|
package/_module/util/Signal.ts
CHANGED
|
@@ -1,33 +1,97 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Function signature for signal subscription callbacks.
|
|
3
|
+
*
|
|
4
|
+
* @template T Payload type emitted by the signal
|
|
5
|
+
*/
|
|
6
|
+
export type SubscriptionCallback<T> = (data: T) => void;
|
|
2
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Lightweight signal / event dispatcher inspired by Godot's signal system.
|
|
10
|
+
*
|
|
11
|
+
* Signals allow decoupled communication by emitting typed payloads to
|
|
12
|
+
* subscribed listeners.
|
|
13
|
+
*
|
|
14
|
+
* @template T Payload type (use `void` for no data)
|
|
15
|
+
*/
|
|
3
16
|
export class Signal<T = void> {
|
|
4
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Registered signal listeners.
|
|
19
|
+
*/
|
|
20
|
+
private readonly listeners = new Set<SubscriptionCallback<T>>();
|
|
5
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Number of currently subscribed listeners.
|
|
24
|
+
*/
|
|
6
25
|
public get count(): number {
|
|
7
26
|
return this.listeners.size;
|
|
8
27
|
}
|
|
9
28
|
|
|
10
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Subscribes a callback to this signal.
|
|
31
|
+
*
|
|
32
|
+
* The callback will be invoked every time the signal is emitted
|
|
33
|
+
* until it is explicitly unsubscribed or the signal is cleared.
|
|
34
|
+
*
|
|
35
|
+
* @param callback Function invoked on signal emission
|
|
36
|
+
*/
|
|
37
|
+
public subscribe(callback: SubscriptionCallback<T>): void {
|
|
11
38
|
this.listeners.add(callback);
|
|
12
39
|
}
|
|
13
40
|
|
|
14
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Unsubscribes a previously registered callback.
|
|
43
|
+
*
|
|
44
|
+
* @param callback Callback to remove
|
|
45
|
+
* @returns `true` if the callback was removed, `false` otherwise
|
|
46
|
+
*/
|
|
47
|
+
public unsubscribe(callback: SubscriptionCallback<T>): boolean {
|
|
15
48
|
return this.listeners.delete(callback);
|
|
16
49
|
}
|
|
17
50
|
|
|
51
|
+
/**
|
|
52
|
+
* Removes all subscribed listeners from this signal.
|
|
53
|
+
*/
|
|
18
54
|
public clear(): void {
|
|
19
55
|
this.listeners.clear();
|
|
20
56
|
}
|
|
21
57
|
|
|
22
|
-
|
|
58
|
+
/**
|
|
59
|
+
* Checks whether a callback is currently subscribed.
|
|
60
|
+
*
|
|
61
|
+
* @param callback Callback to test
|
|
62
|
+
* @returns `true` if the callback is subscribed
|
|
63
|
+
*/
|
|
64
|
+
public isSubscribed(callback: SubscriptionCallback<T>): boolean {
|
|
23
65
|
return this.listeners.has(callback);
|
|
24
66
|
}
|
|
25
67
|
|
|
68
|
+
/**
|
|
69
|
+
* Emits the signal immediately, invoking all subscribed callbacks.
|
|
70
|
+
*
|
|
71
|
+
* Listener errors are caught and logged to prevent a single failure
|
|
72
|
+
* from interrupting signal propagation.
|
|
73
|
+
*
|
|
74
|
+
* @param data Payload to pass to listeners
|
|
75
|
+
*/
|
|
26
76
|
public emit(data: T): void {
|
|
27
77
|
for (const callback of Array.from(this.listeners)) {
|
|
28
|
-
try {
|
|
29
|
-
|
|
78
|
+
try {
|
|
79
|
+
callback(data);
|
|
80
|
+
} catch (err) {
|
|
81
|
+
console.error("BFLIB: Subscription listener error:", err);
|
|
30
82
|
}
|
|
31
83
|
}
|
|
32
84
|
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Emits the signal asynchronously on the microtask queue.
|
|
88
|
+
*
|
|
89
|
+
* Useful for deferring execution to avoid re-entrancy issues
|
|
90
|
+
* or emitting during unsafe execution phases.
|
|
91
|
+
*
|
|
92
|
+
* @param data Payload to pass to listeners
|
|
93
|
+
*/
|
|
94
|
+
public emitDeferred(data: T): void {
|
|
95
|
+
queueMicrotask(() => this.emit(data));
|
|
96
|
+
}
|
|
33
97
|
}
|