bun-memory 1.1.12 → 1.1.14
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/README.md +92 -23
- package/example/trigger-bot.ts +15 -14
- package/package.json +1 -1
- package/structs/Memory.ts +288 -70
- package/types/Memory.ts +91 -0
package/README.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# bun-memory
|
|
2
2
|
|
|
3
|
-
High-performance Windows process memory utilities for [Bun](https://bun.sh) using `bun:ffi` and
|
|
3
|
+
High-performance Windows process memory utilities for [Bun](https://bun.sh) using `bun:ffi` and
|
|
4
|
+
Win32 APIs.
|
|
4
5
|
|
|
5
6
|
## Features
|
|
6
7
|
|
|
@@ -24,7 +25,7 @@ bun add bun-memory
|
|
|
24
25
|
|
|
25
26
|
## Usage
|
|
26
27
|
|
|
27
|
-
See [example/trigger-bot.ts](example/trigger-bot.ts) for a real-world example.
|
|
28
|
+
See [example/trigger-bot.ts](example/trigger-bot.ts) for a real-world example for Counter-Strike 2.
|
|
28
29
|
|
|
29
30
|
### Basic Example
|
|
30
31
|
|
|
@@ -32,42 +33,95 @@ See [example/trigger-bot.ts](example/trigger-bot.ts) for a real-world example.
|
|
|
32
33
|
import Memory from 'bun-memory';
|
|
33
34
|
|
|
34
35
|
// Attach to process by name…
|
|
35
|
-
const memory = new Memory('
|
|
36
|
-
// …or PID
|
|
37
|
-
const memory = new Memory(
|
|
36
|
+
const memory = new Memory('cs2.exe');
|
|
37
|
+
// …or PID…
|
|
38
|
+
const memory = new Memory(1_234);
|
|
38
39
|
|
|
39
|
-
// Access loaded modules
|
|
40
|
+
// Access loaded modules…
|
|
40
41
|
const modules = memory.modules;
|
|
41
|
-
const mainModule = modules['notepad.exe'];
|
|
42
|
-
console.log(`Base address: 0x${mainModule.modBaseAddr.toString(16)}`);
|
|
43
|
-
console.log(`Size: ${mainModule.modBaseSize} bytes`);
|
|
44
42
|
|
|
45
|
-
|
|
46
|
-
const value = memory.i32(0x12345678n);
|
|
43
|
+
const client = modules['client.dll'];
|
|
47
44
|
|
|
48
|
-
|
|
49
|
-
|
|
45
|
+
console.log(`Base address: 0x${client.base.toString(16)}`);
|
|
46
|
+
console.log(`Size: ${client.size} bytes`);
|
|
50
47
|
|
|
51
|
-
//
|
|
48
|
+
// Read a 32-bit integer…
|
|
49
|
+
const value = memory.i32(client.base + 0x12345678n);
|
|
50
|
+
|
|
51
|
+
// Write a float…
|
|
52
|
+
memory.f32(client.base + 0x12345678n, 3.14159);
|
|
53
|
+
|
|
54
|
+
// Clean up…
|
|
52
55
|
memory.close();
|
|
53
56
|
```
|
|
54
57
|
|
|
55
|
-
###
|
|
58
|
+
### API — Typed Reads / Writes
|
|
59
|
+
|
|
60
|
+
A `Memory` instance exposes typed helpers for reading and writing process memory. Pairs indicate
|
|
61
|
+
scalar and array variants; entries without a pair are scalar-only or array-only.
|
|
62
|
+
|
|
63
|
+
- bool
|
|
64
|
+
- cString
|
|
65
|
+
- f32 / f32Array
|
|
66
|
+
- f64 / f64Array
|
|
67
|
+
- i16 / i16Array
|
|
68
|
+
- i32 / i32Array
|
|
69
|
+
- i64 / i64Array
|
|
70
|
+
- i8 / i8Array
|
|
71
|
+
- matrix3x3
|
|
72
|
+
- matrix3x4
|
|
73
|
+
- matrix4x4
|
|
74
|
+
- networkUtlVector
|
|
75
|
+
- qAngle / qAngleArray
|
|
76
|
+
- quaternion / quaternionArray
|
|
77
|
+
- u16 / u16Array
|
|
78
|
+
- u32 / u32Array
|
|
79
|
+
- u64 / u64Array
|
|
80
|
+
- u8 / u8Array
|
|
81
|
+
- vector2 / vector2Array
|
|
82
|
+
- vector3 / vector3Array
|
|
83
|
+
- vector4 / vector4Array
|
|
84
|
+
|
|
85
|
+
### Efficient Reads / Writes Using Scratches
|
|
86
|
+
|
|
87
|
+
There are many ways to use `scratch`es. Scratches are great for avoiding allocation costs by reusing
|
|
88
|
+
a preexisting array, buffer, string, etc.
|
|
56
89
|
|
|
57
90
|
```ts
|
|
58
|
-
const
|
|
59
|
-
const value = memory.bool(offset + 0x1234n);
|
|
60
|
-
memory.close();
|
|
61
|
-
```
|
|
91
|
+
const handles = new Uint32Array(0x100);
|
|
62
92
|
|
|
63
|
-
|
|
93
|
+
while (true) {
|
|
94
|
+
try {
|
|
95
|
+
memory.read(myAddress, handles); // Updated handles, no allocations…
|
|
96
|
+
|
|
97
|
+
// Do something with your handles…
|
|
98
|
+
for (const handle of handles) {
|
|
99
|
+
// …
|
|
100
|
+
}
|
|
101
|
+
} finally {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
```
|
|
64
106
|
|
|
65
107
|
```ts
|
|
66
|
-
const
|
|
67
|
-
const
|
|
108
|
+
const buffer = Buffer.allocUnsafe(0xf000); // Use buffer as a scratch…
|
|
109
|
+
const pointers = new BigUint64Array(scratchBuffer.buffer, scratchBuffer.byteOffset, 0xf000 / 8);
|
|
68
110
|
|
|
69
111
|
while (true) {
|
|
70
|
-
|
|
112
|
+
try {
|
|
113
|
+
memory.read(myAddress, buffer); // Updates buffer and pointers, no allocations…
|
|
114
|
+
|
|
115
|
+
// Do something with your pointers…
|
|
116
|
+
for (const pointer of pointers) {
|
|
117
|
+
// Read a 32 length string at pointer…
|
|
118
|
+
const myString = memory.cString(pointer, 32).toString();
|
|
119
|
+
|
|
120
|
+
// …
|
|
121
|
+
}
|
|
122
|
+
} finally {
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
71
125
|
}
|
|
72
126
|
```
|
|
73
127
|
|
|
@@ -76,6 +130,21 @@ const scratch = Buffer.allocUnsafe(0x100);
|
|
|
76
130
|
memory.read(myAddress, scratch);
|
|
77
131
|
```
|
|
78
132
|
|
|
133
|
+
```ts
|
|
134
|
+
const scratch = new Uint32Array(0x10);
|
|
135
|
+
memory.read(myAddress, scratch);
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Pattern Scanning
|
|
139
|
+
|
|
140
|
+
Pattern scanning is temporarily disabled but will return shortly.
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
const offset = memory.findPattern('aa??bbccdd??ff', mainModule.modBaseAddr, mainModule.modBaseSize);
|
|
144
|
+
const value = memory.bool(offset + 0x1234n);
|
|
145
|
+
memory.close();
|
|
146
|
+
```
|
|
147
|
+
|
|
79
148
|
## Notes
|
|
80
149
|
|
|
81
150
|
- Only works with Bun and Windows.
|
package/example/trigger-bot.ts
CHANGED
|
@@ -11,15 +11,6 @@ import OffsetsJSON from './offsets/offsets.json';
|
|
|
11
11
|
|
|
12
12
|
const { random } = Math;
|
|
13
13
|
|
|
14
|
-
// !
|
|
15
|
-
const buffer = Buffer.from('Hello world!');
|
|
16
|
-
const bufferPtr = ptr(buffer);
|
|
17
|
-
|
|
18
|
-
const cString = new CString(bufferPtr);
|
|
19
|
-
|
|
20
|
-
console.log(cString.byteLength, cString.byteOffset); // undefined undefined
|
|
21
|
-
// !
|
|
22
|
-
|
|
23
14
|
const Delay = 2.5;
|
|
24
15
|
|
|
25
16
|
// Load user32.dll…
|
|
@@ -54,14 +45,24 @@ if (ClientPtr === undefined) {
|
|
|
54
45
|
}
|
|
55
46
|
// !
|
|
56
47
|
|
|
57
|
-
|
|
48
|
+
const dec = new TextDecoder('utf-8');
|
|
58
49
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
50
|
+
const buffer = Buffer.allocUnsafe(32);
|
|
51
|
+
const pointers = [4749947025128n, 4749937696488n, 4749757372648n, 4745786211048n, 4745800086248n, 4748263960808n, 4748274490088n, 4748287459048n, 4747096900328n, 4747107757288n];
|
|
52
|
+
|
|
53
|
+
console.time('test');
|
|
54
|
+
|
|
55
|
+
while (true) {
|
|
56
|
+
for (const pointer of pointers) {
|
|
57
|
+
const cString = cs2.cString(pointer, 32).toString();
|
|
58
|
+
|
|
59
|
+
if (cString.length > 32) {
|
|
60
|
+
console.log(cString);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
62
63
|
}
|
|
63
64
|
|
|
64
|
-
console.timeEnd('
|
|
65
|
+
console.timeEnd('test');
|
|
65
66
|
|
|
66
67
|
// !
|
|
67
68
|
|
package/package.json
CHANGED
package/structs/Memory.ts
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
// TODO: Reintroduce findPattern(…)…
|
|
2
|
-
// TODO: Reintroduce indexOf(…)…
|
|
3
|
-
// TODO: String methods…
|
|
4
|
-
|
|
5
1
|
import { CString, FFIType, dlopen, read } from 'bun:ffi';
|
|
6
2
|
|
|
7
|
-
import type { Module, NetworkUtlVector, Quaternion, Region, Scratch, Vector2, Vector3 } from '../types/Memory';
|
|
3
|
+
import type { Module, NetworkUtlVector, QAngle, Quaternion, Region, Scratch, Vector2, Vector3, Vector4 } from '../types/Memory';
|
|
8
4
|
import Win32Error from './Win32Error';
|
|
9
5
|
|
|
10
6
|
const { f32, f64, i16, i32, i64, i8, u16, u32, u64, u8 } = read;
|
|
@@ -33,6 +29,9 @@ const { symbols: Kernel32 } = dlopen('kernel32.dll', {
|
|
|
33
29
|
* This class allows reading from and writing to memory addresses in external processes,
|
|
34
30
|
* supporting various data types including primitives, arrays, and custom structures like vectors and quaternions.
|
|
35
31
|
*
|
|
32
|
+
* @todo Reimplement `findPattern(…)`.
|
|
33
|
+
* @todo Reimplement `indexOf(…)`.
|
|
34
|
+
*
|
|
36
35
|
* @example
|
|
37
36
|
* ```typescript
|
|
38
37
|
* // Connect to a process by name
|
|
@@ -168,6 +167,18 @@ class Memory {
|
|
|
168
167
|
private readonly ScratchMemoryBasicInformation = Buffer.allocUnsafe(0x30 /* sizeof(MEMORY_BASIC_INFORMATION) */);
|
|
169
168
|
private readonly ScratchModuleEntry32W = Buffer.allocUnsafe(0x438 /* sizeof(MODULEENTRY32W) */);
|
|
170
169
|
|
|
170
|
+
/**
|
|
171
|
+
* Reusable UTF-16 decoder for interpreting raw process memory as UTF-16 text.
|
|
172
|
+
* Kept as a singleton to avoid repeated allocations in hot paths.
|
|
173
|
+
*/
|
|
174
|
+
private static readonly TextDecoderUTF16 = new TextDecoder('utf-16');
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Reusable UTF-8 decoder for interpreting raw process memory as UTF-8 text.
|
|
178
|
+
* Kept as a singleton to avoid repeated allocations in hot paths.
|
|
179
|
+
*/
|
|
180
|
+
private static readonly TextDecoderUTF8 = new TextDecoder('utf-8');
|
|
181
|
+
|
|
171
182
|
/**
|
|
172
183
|
* Handle to the target process.
|
|
173
184
|
*/
|
|
@@ -185,7 +196,6 @@ class Memory {
|
|
|
185
196
|
*
|
|
186
197
|
* @example
|
|
187
198
|
* ```typescript
|
|
188
|
-
* const memory = new Memory('notepad.exe');
|
|
189
199
|
* const modules = memory.modules;
|
|
190
200
|
*
|
|
191
201
|
* // Access a specific module
|
|
@@ -211,7 +221,6 @@ class Memory {
|
|
|
211
221
|
*
|
|
212
222
|
* @example
|
|
213
223
|
* ```typescript
|
|
214
|
-
* const memory = new Memory('notepad.exe');
|
|
215
224
|
* const regions = memory.regions(0x10000000n, 0x1000n);
|
|
216
225
|
*
|
|
217
226
|
* regions.forEach(region => {
|
|
@@ -265,7 +274,6 @@ class Memory {
|
|
|
265
274
|
*
|
|
266
275
|
* @example
|
|
267
276
|
* ```typescript
|
|
268
|
-
* const memory = new Memory('notepad.exe');
|
|
269
277
|
* const buffer = new Uint8Array(4);
|
|
270
278
|
* memory.read(0x12345678n, buffer);
|
|
271
279
|
* ```
|
|
@@ -295,7 +303,6 @@ class Memory {
|
|
|
295
303
|
*
|
|
296
304
|
* @example
|
|
297
305
|
* ```typescript
|
|
298
|
-
* const memory = new Memory('notepad.exe');
|
|
299
306
|
* const buffer = new Uint8Array([0x41, 0x42, 0x43, 0x44]);
|
|
300
307
|
* memory.write(0x12345678n, buffer);
|
|
301
308
|
* ```
|
|
@@ -342,8 +349,6 @@ class Memory {
|
|
|
342
349
|
*
|
|
343
350
|
* @example
|
|
344
351
|
* ```typescript
|
|
345
|
-
* const memory = new Memory('notepad.exe');
|
|
346
|
-
*
|
|
347
352
|
* // Initial modules
|
|
348
353
|
* console.log('Initial modules:', Object.keys(memory.modules));
|
|
349
354
|
*
|
|
@@ -401,8 +406,6 @@ class Memory {
|
|
|
401
406
|
*
|
|
402
407
|
* @example
|
|
403
408
|
* ```typescript
|
|
404
|
-
* const memory = new Memory('game.exe');
|
|
405
|
-
*
|
|
406
409
|
* // Read a boolean value
|
|
407
410
|
* const isAlive = memory.bool(0x12345678n);
|
|
408
411
|
* console.log('Player is alive:', isAlive);
|
|
@@ -444,14 +447,14 @@ class Memory {
|
|
|
444
447
|
*
|
|
445
448
|
* @example
|
|
446
449
|
* ```typescript
|
|
447
|
-
* const memory = new Memory('game.exe');
|
|
448
|
-
*
|
|
449
450
|
* // Read up to 64 bytes and interpret as a C string
|
|
450
451
|
* const playerName = memory.cString(0x12345678n, 64);
|
|
451
452
|
* console.log('Player name:', playerName.toString());
|
|
452
453
|
*
|
|
453
454
|
* // Write a C string (NUL-terminated)
|
|
454
|
-
* const
|
|
455
|
+
* const valueBuffer = Buffer.from('PlayerOne\0');
|
|
456
|
+
* const valuePtr = ptr(valueBuffer);
|
|
457
|
+
* const value = new CString(valuePtr);
|
|
455
458
|
* memory.cString(0x12345678n, value);
|
|
456
459
|
* ```
|
|
457
460
|
*/
|
|
@@ -482,8 +485,6 @@ class Memory {
|
|
|
482
485
|
*
|
|
483
486
|
* @example
|
|
484
487
|
* ```typescript
|
|
485
|
-
* const memory = new Memory('game.exe');
|
|
486
|
-
*
|
|
487
488
|
* // Read a float value
|
|
488
489
|
* const playerHealth = memory.f32(0x12345678n);
|
|
489
490
|
* console.log('Player health:', playerHealth);
|
|
@@ -517,8 +518,6 @@ class Memory {
|
|
|
517
518
|
*
|
|
518
519
|
* @example
|
|
519
520
|
* ```typescript
|
|
520
|
-
* const memory = new Memory('game.exe');
|
|
521
|
-
*
|
|
522
521
|
* // Read an array of 10 float values
|
|
523
522
|
* const coordinates = memory.f32Array(0x12345678n, 10);
|
|
524
523
|
* console.log('Coordinates:', coordinates);
|
|
@@ -556,8 +555,6 @@ class Memory {
|
|
|
556
555
|
*
|
|
557
556
|
* @example
|
|
558
557
|
* ```typescript
|
|
559
|
-
* const memory = new Memory('scientific_app.exe');
|
|
560
|
-
*
|
|
561
558
|
* // Read a double precision value
|
|
562
559
|
* const preciseValue = memory.f64(0x12345678n);
|
|
563
560
|
* console.log('Precise value:', preciseValue);
|
|
@@ -591,8 +588,6 @@ class Memory {
|
|
|
591
588
|
*
|
|
592
589
|
* @example
|
|
593
590
|
* ```typescript
|
|
594
|
-
* const memory = new Memory('scientific_app.exe');
|
|
595
|
-
*
|
|
596
591
|
* // Read an array of 5 double precision values
|
|
597
592
|
* const preciseData = memory.f64Array(0x12345678n, 5);
|
|
598
593
|
* console.log('Precise data:', preciseData);
|
|
@@ -630,8 +625,6 @@ class Memory {
|
|
|
630
625
|
*
|
|
631
626
|
* @example
|
|
632
627
|
* ```typescript
|
|
633
|
-
* const memory = new Memory('game.exe');
|
|
634
|
-
*
|
|
635
628
|
* // Read a signed 16-bit integer
|
|
636
629
|
* const temperature = memory.i16(0x12345678n);
|
|
637
630
|
* console.log('Temperature:', temperature);
|
|
@@ -665,8 +658,6 @@ class Memory {
|
|
|
665
658
|
*
|
|
666
659
|
* @example
|
|
667
660
|
* ```typescript
|
|
668
|
-
* const memory = new Memory('audio_app.exe');
|
|
669
|
-
*
|
|
670
661
|
* // Read an array of audio samples
|
|
671
662
|
* const samples = memory.i16Array(0x12345678n, 1024);
|
|
672
663
|
* console.log('Audio samples:', samples);
|
|
@@ -704,8 +695,6 @@ class Memory {
|
|
|
704
695
|
*
|
|
705
696
|
* @example
|
|
706
697
|
* ```typescript
|
|
707
|
-
* const memory = new Memory('game.exe');
|
|
708
|
-
*
|
|
709
698
|
* // Read a player's score
|
|
710
699
|
* const score = memory.i32(0x12345678n);
|
|
711
700
|
* console.log('Player score:', score);
|
|
@@ -739,8 +728,6 @@ class Memory {
|
|
|
739
728
|
*
|
|
740
729
|
* @example
|
|
741
730
|
* ```typescript
|
|
742
|
-
* const memory = new Memory('game.exe');
|
|
743
|
-
*
|
|
744
731
|
* // Read inventory item counts
|
|
745
732
|
* const inventory = memory.i32Array(0x12345678n, 20);
|
|
746
733
|
* console.log('Inventory:', inventory);
|
|
@@ -778,8 +765,6 @@ class Memory {
|
|
|
778
765
|
*
|
|
779
766
|
* @example
|
|
780
767
|
* ```typescript
|
|
781
|
-
* const memory = new Memory('database.exe');
|
|
782
|
-
*
|
|
783
768
|
* // Read a large number (timestamp, file size, etc.)
|
|
784
769
|
* const timestamp = memory.i64(0x12345678n);
|
|
785
770
|
* console.log('Timestamp:', timestamp);
|
|
@@ -813,8 +798,6 @@ class Memory {
|
|
|
813
798
|
*
|
|
814
799
|
* @example
|
|
815
800
|
* ```typescript
|
|
816
|
-
* const memory = new Memory('database.exe');
|
|
817
|
-
*
|
|
818
801
|
* // Read an array of large numbers
|
|
819
802
|
* const largeNumbers = memory.i64Array(0x12345678n, 10);
|
|
820
803
|
* console.log('Large numbers:', largeNumbers);
|
|
@@ -852,8 +835,6 @@ class Memory {
|
|
|
852
835
|
*
|
|
853
836
|
* @example
|
|
854
837
|
* ```typescript
|
|
855
|
-
* const memory = new Memory('game.exe');
|
|
856
|
-
*
|
|
857
838
|
* // Read a small signed value (e.g., direction, state)
|
|
858
839
|
* const direction = memory.i8(0x12345678n);
|
|
859
840
|
* console.log('Direction:', direction);
|
|
@@ -887,8 +868,6 @@ class Memory {
|
|
|
887
868
|
*
|
|
888
869
|
* @example
|
|
889
870
|
* ```typescript
|
|
890
|
-
* const memory = new Memory('game.exe');
|
|
891
|
-
*
|
|
892
871
|
* // Read an array of small signed values
|
|
893
872
|
* const directions = memory.i8Array(0x12345678n, 8);
|
|
894
873
|
* console.log('Movement directions:', directions);
|
|
@@ -917,6 +896,117 @@ class Memory {
|
|
|
917
896
|
return this;
|
|
918
897
|
}
|
|
919
898
|
|
|
899
|
+
/**
|
|
900
|
+
* Reads a 3×3 matrix from memory or writes a 3×3 matrix to memory.
|
|
901
|
+
*
|
|
902
|
+
* The matrix is represented as 9 contiguous 32-bit floating-point values (`Float32Array`).
|
|
903
|
+
* No transposition or stride is applied—values are copied exactly as stored in memory.
|
|
904
|
+
*
|
|
905
|
+
* @param address - Memory address to read from or write to
|
|
906
|
+
* @param values - Optional `Float32Array` of length 9 to write. If omitted, performs a read operation
|
|
907
|
+
* @returns `Float32Array` of length 9 when reading, or this `Memory` instance when writing
|
|
908
|
+
* @throws {RangeError} When `values.length` is not exactly 9
|
|
909
|
+
*
|
|
910
|
+
* @example
|
|
911
|
+
* ```typescript
|
|
912
|
+
* // Read a 3×3 matrix
|
|
913
|
+
* const matrix = memory.matrix3x3(0x12345678n); // Float32Array(9)
|
|
914
|
+
*
|
|
915
|
+
* // Write a 3×3 matrix (length must be 9)
|
|
916
|
+
* const next = new Float32Array([
|
|
917
|
+
* 1, 0, 0,
|
|
918
|
+
* 0, 1, 0,
|
|
919
|
+
* 0, 0, 1
|
|
920
|
+
* ]);
|
|
921
|
+
* memory.matrix3x3(0x12345678n, next);
|
|
922
|
+
* ```
|
|
923
|
+
*/
|
|
924
|
+
public matrix3x3(address: bigint): Float32Array;
|
|
925
|
+
public matrix3x3(address: bigint, values: Float32Array): this;
|
|
926
|
+
public matrix3x3(address: bigint, values?: Float32Array): Float32Array | this {
|
|
927
|
+
if (values === undefined) {
|
|
928
|
+
const scratch = new Float32Array(0x09);
|
|
929
|
+
|
|
930
|
+
this.read(address, scratch);
|
|
931
|
+
|
|
932
|
+
return scratch;
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
if (values.length !== 0x09) {
|
|
936
|
+
throw new RangeError('values.length must be 9.');
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
this.write(address, values);
|
|
940
|
+
|
|
941
|
+
return this;
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
public matrix3x4(address: bigint): Float32Array;
|
|
945
|
+
public matrix3x4(address: bigint, values: Float32Array): this;
|
|
946
|
+
public matrix3x4(address: bigint, values?: Float32Array): Float32Array | this {
|
|
947
|
+
if (values === undefined) {
|
|
948
|
+
const scratch = new Float32Array(0x0c);
|
|
949
|
+
|
|
950
|
+
this.read(address, scratch);
|
|
951
|
+
|
|
952
|
+
return scratch;
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
if (values.length !== 0x0c) {
|
|
956
|
+
throw new RangeError('values.length must be 12.');
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
this.write(address, values);
|
|
960
|
+
|
|
961
|
+
return this;
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
/**
|
|
965
|
+
* Reads a 4×4 matrix from memory or writes a 4×4 matrix to memory.
|
|
966
|
+
*
|
|
967
|
+
* The matrix is represented as 16 contiguous 32-bit floating-point values (`Float32Array`).
|
|
968
|
+
* No transposition or stride is applied—values are copied exactly as stored in memory.
|
|
969
|
+
*
|
|
970
|
+
* @param address - Memory address to read from or write to
|
|
971
|
+
* @param values - Optional `Float32Array` of length 16 to write. If omitted, performs a read operation
|
|
972
|
+
* @returns `Float32Array` of length 16 when reading, or this `Memory` instance when writing
|
|
973
|
+
* @throws {RangeError} When `values.length` is not exactly 16
|
|
974
|
+
*
|
|
975
|
+
* @example
|
|
976
|
+
* ```typescript
|
|
977
|
+
* // Read a 4×4 matrix
|
|
978
|
+
* const matrix = memory.matrix4x4(0x12345678n); // Float32Array(16)
|
|
979
|
+
*
|
|
980
|
+
* // Write a 4×4 matrix (length must be 16)
|
|
981
|
+
* const next = new Float32Array([
|
|
982
|
+
* 1, 0, 0, 0,
|
|
983
|
+
* 0, 1, 0, 0,
|
|
984
|
+
* 0, 0, 1, 0,
|
|
985
|
+
* 0, 0, 0, 1
|
|
986
|
+
* ]);
|
|
987
|
+
* memory.matrix4x4(0x12345678n, next);
|
|
988
|
+
* ```
|
|
989
|
+
*/
|
|
990
|
+
public matrix4x4(address: bigint): Float32Array;
|
|
991
|
+
public matrix4x4(address: bigint, values: Float32Array): this;
|
|
992
|
+
public matrix4x4(address: bigint, values?: Float32Array): Float32Array | this {
|
|
993
|
+
if (values === undefined) {
|
|
994
|
+
const scratch = new Float32Array(0x10);
|
|
995
|
+
|
|
996
|
+
this.read(address, scratch);
|
|
997
|
+
|
|
998
|
+
return scratch;
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
if (values.length !== 0x10) {
|
|
1002
|
+
throw new RangeError('values.length must be 16.');
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
this.write(address, values);
|
|
1006
|
+
|
|
1007
|
+
return this;
|
|
1008
|
+
}
|
|
1009
|
+
|
|
920
1010
|
/**
|
|
921
1011
|
* Reads a `NetworkUtlVector` (`Uint32Array`) from memory or writes a `NetworkUtlVector` to memory.
|
|
922
1012
|
*
|
|
@@ -936,8 +1026,6 @@ class Memory {
|
|
|
936
1026
|
*
|
|
937
1027
|
* @example
|
|
938
1028
|
* ```typescript
|
|
939
|
-
* const memory = new Memory('network_app.exe');
|
|
940
|
-
*
|
|
941
1029
|
* // Read the current vector
|
|
942
1030
|
* const ids = memory.networkUtlVector(0x12345678n);
|
|
943
1031
|
* console.log('IDs:', Array.from(ids));
|
|
@@ -969,6 +1057,103 @@ class Memory {
|
|
|
969
1057
|
return this;
|
|
970
1058
|
}
|
|
971
1059
|
|
|
1060
|
+
/**
|
|
1061
|
+
* Reads a set of Euler angles from memory or writes a set of Euler angles to memory.
|
|
1062
|
+
*
|
|
1063
|
+
* Angles are stored as three 32-bit floats in the order **pitch, yaw, roll**.
|
|
1064
|
+
*
|
|
1065
|
+
* @param address - Memory address to read from or write to
|
|
1066
|
+
* @param value - Optional `QAngle` to write. If omitted, performs a read operation
|
|
1067
|
+
* @returns The `QAngle` value when reading, or this `Memory` instance when writing
|
|
1068
|
+
*
|
|
1069
|
+
* @example
|
|
1070
|
+
* ```typescript
|
|
1071
|
+
* // Read current view angles
|
|
1072
|
+
* const view = memory.qAngle(0x12345678n);
|
|
1073
|
+
*
|
|
1074
|
+
* // Write new view angles (e.g., level the roll)
|
|
1075
|
+
* memory.qAngle(0x12345678n, { ...view, roll: 0 });
|
|
1076
|
+
* ```
|
|
1077
|
+
*/
|
|
1078
|
+
|
|
1079
|
+
public qAngle(address: bigint): QAngle;
|
|
1080
|
+
public qAngle(address: bigint, value: QAngle): this;
|
|
1081
|
+
public qAngle(address: bigint, value?: QAngle): QAngle | this {
|
|
1082
|
+
if (value === undefined) {
|
|
1083
|
+
this.read(address, this.Scratch12);
|
|
1084
|
+
|
|
1085
|
+
const pitch = f32(this.Scratch12.ptr);
|
|
1086
|
+
const roll = f32(this.Scratch12.ptr, 0x08);
|
|
1087
|
+
const yaw = f32(this.Scratch12.ptr, 0x04);
|
|
1088
|
+
|
|
1089
|
+
return { pitch, roll, yaw };
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
this.Scratch12Buffer.writeFloatLE(value.pitch);
|
|
1093
|
+
this.Scratch12Buffer.writeFloatLE(value.roll, 0x08);
|
|
1094
|
+
this.Scratch12Buffer.writeFloatLE(value.yaw, 0x04);
|
|
1095
|
+
|
|
1096
|
+
this.write(address, this.Scratch12);
|
|
1097
|
+
|
|
1098
|
+
return this;
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
/**
|
|
1102
|
+
* Reads an array of Euler angles from memory or writes an array of Euler angles to memory.
|
|
1103
|
+
*
|
|
1104
|
+
* Each element is three 32-bit floats in the order **pitch, yaw, roll**.
|
|
1105
|
+
*
|
|
1106
|
+
* @param address - Memory address to read from or write to
|
|
1107
|
+
* @param lengthOrValues - Length of array to read, or array of `QAngle` values to write
|
|
1108
|
+
* @returns `QAngle[]` when reading, or this `Memory` instance when writing
|
|
1109
|
+
*
|
|
1110
|
+
* @example
|
|
1111
|
+
* ```typescript
|
|
1112
|
+
* // Read bone aim offsets
|
|
1113
|
+
* const bones = memory.qAngleArray(0x12345678n, 64);
|
|
1114
|
+
*
|
|
1115
|
+
* // Write new bone angles (e.g., reset all roll to zero)
|
|
1116
|
+
* bones.forEach(b => (b.roll = 0));
|
|
1117
|
+
* memory.qAngleArray(0x12345678n, bones);
|
|
1118
|
+
* ```
|
|
1119
|
+
*/
|
|
1120
|
+
public qAngleArray(address: bigint, length: number): QAngle[];
|
|
1121
|
+
public qAngleArray(address: bigint, values: QAngle[]): this;
|
|
1122
|
+
public qAngleArray(address: bigint, lengthOrValues: QAngle[] | number): QAngle[] | this {
|
|
1123
|
+
if (typeof lengthOrValues === 'number') {
|
|
1124
|
+
const length = lengthOrValues;
|
|
1125
|
+
const scratch = new Float32Array(length * 0x03);
|
|
1126
|
+
|
|
1127
|
+
this.read(address, scratch);
|
|
1128
|
+
|
|
1129
|
+
const result = new Array<QAngle>(length);
|
|
1130
|
+
|
|
1131
|
+
for (let i = 0, j = 0; i < length; i++, j += 0x03) {
|
|
1132
|
+
const pitch = scratch[j];
|
|
1133
|
+
const yaw = scratch[j + 0x01];
|
|
1134
|
+
const roll = scratch[j + 0x02];
|
|
1135
|
+
result[i] = { pitch, yaw, roll };
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
return result;
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
const values = lengthOrValues;
|
|
1142
|
+
const scratch = new Float32Array(values.length * 0x03);
|
|
1143
|
+
|
|
1144
|
+
for (let i = 0, j = 0; i < values.length; i++, j += 0x03) {
|
|
1145
|
+
const qAngle = values[i];
|
|
1146
|
+
|
|
1147
|
+
scratch[j] = qAngle.pitch;
|
|
1148
|
+
scratch[j + 0x02] = qAngle.roll;
|
|
1149
|
+
scratch[j + 0x01] = qAngle.yaw;
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
this.write(address, scratch);
|
|
1153
|
+
|
|
1154
|
+
return this;
|
|
1155
|
+
}
|
|
1156
|
+
|
|
972
1157
|
/**
|
|
973
1158
|
* Reads a quaternion (4D rotation) from memory or writes a quaternion to memory.
|
|
974
1159
|
* Quaternions are stored as four 32-bit floats: x, y, z, w.
|
|
@@ -979,8 +1164,6 @@ class Memory {
|
|
|
979
1164
|
*
|
|
980
1165
|
* @example
|
|
981
1166
|
* ```typescript
|
|
982
|
-
* const memory = new Memory('game.exe');
|
|
983
|
-
*
|
|
984
1167
|
* // Read player rotation
|
|
985
1168
|
* const rotation = memory.quaternion(0x12345678n);
|
|
986
1169
|
* console.log('Player rotation:', rotation);
|
|
@@ -1022,8 +1205,6 @@ class Memory {
|
|
|
1022
1205
|
*
|
|
1023
1206
|
* @example
|
|
1024
1207
|
* ```typescript
|
|
1025
|
-
* const memory = new Memory('game.exe');
|
|
1026
|
-
*
|
|
1027
1208
|
* // Read bone rotations for skeletal animation
|
|
1028
1209
|
* const boneRotations = memory.quaternionArray(0x12345678n, 50);
|
|
1029
1210
|
* console.log('Bone rotations:', boneRotations);
|
|
@@ -1082,8 +1263,6 @@ class Memory {
|
|
|
1082
1263
|
*
|
|
1083
1264
|
* @example
|
|
1084
1265
|
* ```typescript
|
|
1085
|
-
* const memory = new Memory('game.exe');
|
|
1086
|
-
*
|
|
1087
1266
|
* // Read a port number or small positive value
|
|
1088
1267
|
* const port = memory.u16(0x12345678n);
|
|
1089
1268
|
* console.log('Network port:', port);
|
|
@@ -1117,8 +1296,6 @@ class Memory {
|
|
|
1117
1296
|
*
|
|
1118
1297
|
* @example
|
|
1119
1298
|
* ```typescript
|
|
1120
|
-
* const memory = new Memory('network_app.exe');
|
|
1121
|
-
*
|
|
1122
1299
|
* // Read an array of port numbers
|
|
1123
1300
|
* const ports = memory.u16Array(0x12345678n, 10);
|
|
1124
1301
|
* console.log('Active ports:', ports);
|
|
@@ -1156,8 +1333,6 @@ class Memory {
|
|
|
1156
1333
|
*
|
|
1157
1334
|
* @example
|
|
1158
1335
|
* ```typescript
|
|
1159
|
-
* const memory = new Memory('game.exe');
|
|
1160
|
-
*
|
|
1161
1336
|
* // Read player's money (always positive)
|
|
1162
1337
|
* const money = memory.u32(0x12345678n);
|
|
1163
1338
|
* console.log('Player money:', money);
|
|
@@ -1191,8 +1366,6 @@ class Memory {
|
|
|
1191
1366
|
*
|
|
1192
1367
|
* @example
|
|
1193
1368
|
* ```typescript
|
|
1194
|
-
* const memory = new Memory('game.exe');
|
|
1195
|
-
*
|
|
1196
1369
|
* // Read resource amounts
|
|
1197
1370
|
* const resources = memory.u32Array(0x12345678n, 6);
|
|
1198
1371
|
* console.log('Resources:', resources);
|
|
@@ -1230,8 +1403,6 @@ class Memory {
|
|
|
1230
1403
|
*
|
|
1231
1404
|
* @example
|
|
1232
1405
|
* ```typescript
|
|
1233
|
-
* const memory = new Memory('database.exe');
|
|
1234
|
-
*
|
|
1235
1406
|
* // Read a very large positive number
|
|
1236
1407
|
* const recordId = memory.u64(0x12345678n);
|
|
1237
1408
|
* console.log('Record ID:', recordId);
|
|
@@ -1265,8 +1436,6 @@ class Memory {
|
|
|
1265
1436
|
*
|
|
1266
1437
|
* @example
|
|
1267
1438
|
* ```typescript
|
|
1268
|
-
* const memory = new Memory('database.exe');
|
|
1269
|
-
*
|
|
1270
1439
|
* // Read an array of record IDs
|
|
1271
1440
|
* const recordIds = memory.u64Array(0x12345678n, 100);
|
|
1272
1441
|
* console.log('Record IDs:', recordIds);
|
|
@@ -1304,8 +1473,6 @@ class Memory {
|
|
|
1304
1473
|
*
|
|
1305
1474
|
* @example
|
|
1306
1475
|
* ```typescript
|
|
1307
|
-
* const memory = new Memory('game.exe');
|
|
1308
|
-
*
|
|
1309
1476
|
* // Read a byte value (0-255)
|
|
1310
1477
|
* const opacity = memory.u8(0x12345678n);
|
|
1311
1478
|
* console.log('UI opacity:', opacity);
|
|
@@ -1339,8 +1506,6 @@ class Memory {
|
|
|
1339
1506
|
*
|
|
1340
1507
|
* @example
|
|
1341
1508
|
* ```typescript
|
|
1342
|
-
* const memory = new Memory('image_editor.exe');
|
|
1343
|
-
*
|
|
1344
1509
|
* // Read pixel data
|
|
1345
1510
|
* const pixels = memory.u8Array(0x12345678n, 1024);
|
|
1346
1511
|
* console.log('Pixel data:', pixels);
|
|
@@ -1379,8 +1544,6 @@ class Memory {
|
|
|
1379
1544
|
*
|
|
1380
1545
|
* @example
|
|
1381
1546
|
* ```typescript
|
|
1382
|
-
* const memory = new Memory('game.exe');
|
|
1383
|
-
*
|
|
1384
1547
|
* // Read player position
|
|
1385
1548
|
* const position = memory.vector2(0x12345678n);
|
|
1386
1549
|
* console.log('Player position:', position);
|
|
@@ -1418,8 +1581,6 @@ class Memory {
|
|
|
1418
1581
|
*
|
|
1419
1582
|
* @example
|
|
1420
1583
|
* ```typescript
|
|
1421
|
-
* const memory = new Memory('game.exe');
|
|
1422
|
-
*
|
|
1423
1584
|
* // Read waypoints for AI pathfinding
|
|
1424
1585
|
* const waypoints = memory.vector2Array(0x12345678n, 20);
|
|
1425
1586
|
* console.log('AI waypoints:', waypoints);
|
|
@@ -1479,8 +1640,6 @@ class Memory {
|
|
|
1479
1640
|
*
|
|
1480
1641
|
* @example
|
|
1481
1642
|
* ```typescript
|
|
1482
|
-
* const memory = new Memory('game.exe');
|
|
1483
|
-
*
|
|
1484
1643
|
* // Read player 3D position
|
|
1485
1644
|
* const position = memory.vector3(0x12345678n);
|
|
1486
1645
|
* console.log('Player 3D position:', position);
|
|
@@ -1520,8 +1679,6 @@ class Memory {
|
|
|
1520
1679
|
*
|
|
1521
1680
|
* @example
|
|
1522
1681
|
* ```typescript
|
|
1523
|
-
* const memory = new Memory('game.exe');
|
|
1524
|
-
*
|
|
1525
1682
|
* // Read vertex positions for 3D model
|
|
1526
1683
|
* const vertices = memory.vector3Array(0x12345678n, 500);
|
|
1527
1684
|
* console.log('3D vertices:', vertices);
|
|
@@ -1572,6 +1729,67 @@ class Memory {
|
|
|
1572
1729
|
|
|
1573
1730
|
return this;
|
|
1574
1731
|
}
|
|
1732
|
+
|
|
1733
|
+
/**
|
|
1734
|
+
* Reads a 4D vector from memory or writes a 4D vector to memory.
|
|
1735
|
+
*
|
|
1736
|
+
* Uses the same 16-byte layout as {@link Memory.quaternion}: four 32-bit floats
|
|
1737
|
+
* stored in the order **x, y, z, w**. Returned objects are shaped as `{ w, x, y, z }`.
|
|
1738
|
+
*
|
|
1739
|
+
* @param address - Memory address to read from or write to
|
|
1740
|
+
* @param value - Optional `Vector4` to write. If omitted, performs a read operation
|
|
1741
|
+
* @returns The `Vector4` value when reading, or this `Memory` instance when writing
|
|
1742
|
+
*
|
|
1743
|
+
* @example
|
|
1744
|
+
* ```typescript
|
|
1745
|
+
* // Read directional data in projective space
|
|
1746
|
+
* const value = memory.vector4(0x12345678n);
|
|
1747
|
+
*
|
|
1748
|
+
* // Write a vector4 value (e.g., identity quaternion)
|
|
1749
|
+
* memory.vector4(0x12345678n, { x: 0, y: 0, z: 0, w: 1 });
|
|
1750
|
+
* ```
|
|
1751
|
+
*/
|
|
1752
|
+
public vector4(address: bigint): Vector4;
|
|
1753
|
+
public vector4(address: bigint, value: Vector4): this;
|
|
1754
|
+
public vector4(address: bigint, value?: Vector4): Vector4 | this {
|
|
1755
|
+
// TypeScript is funny sometimes, isn't it?… 🫠…
|
|
1756
|
+
if (value === undefined) {
|
|
1757
|
+
return this.quaternion(address);
|
|
1758
|
+
}
|
|
1759
|
+
|
|
1760
|
+
return this.quaternion(address, value);
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
/**
|
|
1764
|
+
* Reads an array of 4D vectors from memory or writes an array of 4D vectors to memory.
|
|
1765
|
+
*
|
|
1766
|
+
* Each element uses the same 16-byte layout as {@link Memory.quaternionArray}:
|
|
1767
|
+
* four 32-bit floats stored in the order **x, y, z, w**.
|
|
1768
|
+
*
|
|
1769
|
+
* @param address - Memory address to read from or write to
|
|
1770
|
+
* @param lengthOrValues - Length of array to read, or array of `Vector4` values to write
|
|
1771
|
+
* @returns `Vector4[]` when reading, or this `Memory` instance when writing
|
|
1772
|
+
*
|
|
1773
|
+
* @example
|
|
1774
|
+
* ```typescript
|
|
1775
|
+
* // Read per-vertex tangent vectors (xyzw)
|
|
1776
|
+
* const tangents = memory.vector4Array(0x12345678n, 1024);
|
|
1777
|
+
*
|
|
1778
|
+
* // Write tangent vectors (eg. normalize w to 1.0)
|
|
1779
|
+
* tangents.forEach(v => (v.w = 1.0));
|
|
1780
|
+
* memory.vector4Array(0x12345678n, tangents);
|
|
1781
|
+
* ```
|
|
1782
|
+
*/
|
|
1783
|
+
public vector4Array(address: bigint, length: number): Vector4[];
|
|
1784
|
+
public vector4Array(address: bigint, values: Vector4[]): this;
|
|
1785
|
+
public vector4Array(address: bigint, lengthOrValues: Vector4[] | number): Vector4[] | this {
|
|
1786
|
+
// TypeScript is funny sometimes, isn't it?… 🫠…
|
|
1787
|
+
if (typeof lengthOrValues === 'number') {
|
|
1788
|
+
return this.quaternionArray(address, lengthOrValues);
|
|
1789
|
+
}
|
|
1790
|
+
|
|
1791
|
+
return this.quaternionArray(address, lengthOrValues);
|
|
1792
|
+
}
|
|
1575
1793
|
}
|
|
1576
1794
|
|
|
1577
1795
|
export default Memory;
|
package/types/Memory.ts
CHANGED
|
@@ -319,6 +319,68 @@ export type Quaternion = {
|
|
|
319
319
|
z: number;
|
|
320
320
|
};
|
|
321
321
|
|
|
322
|
+
/**
|
|
323
|
+
* Represents an orientation using Euler angles.
|
|
324
|
+
*
|
|
325
|
+
* `QAngle` stores three 32-bit floating-point angles that describe rotation
|
|
326
|
+
* in degrees around the principal axes: `pitch` (X), `yaw` (Y), and `roll` (Z).
|
|
327
|
+
* This format is common in Source-engine-style telemetry and many gameplay
|
|
328
|
+
* camera systems. For quaternions, see {@link Quaternion}.
|
|
329
|
+
*
|
|
330
|
+
* Typical uses include:
|
|
331
|
+
* - Camera/view rotations
|
|
332
|
+
* - Bone/attachment orientations
|
|
333
|
+
* - Aim and recoil calculations
|
|
334
|
+
*
|
|
335
|
+
* @example
|
|
336
|
+
* ```typescript
|
|
337
|
+
* // Read and tweak view angles
|
|
338
|
+
* const view: QAngle = memory.qAngle(0x12345678n);
|
|
339
|
+
* const leveled: QAngle = { pitch: 0, yaw: view.yaw, roll: 0 };
|
|
340
|
+
* memory.qAngle(0x12345678n, leveled);
|
|
341
|
+
* ```
|
|
342
|
+
*/
|
|
343
|
+
export interface QAngle {
|
|
344
|
+
/**
|
|
345
|
+
* Rotation around the X axis, in degrees.
|
|
346
|
+
*
|
|
347
|
+
* Positive values pitch the nose downward in many right-handed game
|
|
348
|
+
* coordinate systems; verify the target engine’s convention before writing.
|
|
349
|
+
*
|
|
350
|
+
* @example
|
|
351
|
+
* ```typescript
|
|
352
|
+
* const aimDown: QAngle = { pitch: 10, yaw: 0, roll: 0 };
|
|
353
|
+
* ```
|
|
354
|
+
*/
|
|
355
|
+
pitch: number;
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Rotation around the Z axis, in degrees.
|
|
359
|
+
*
|
|
360
|
+
* Often used for banking/tilt effects. Some engines clamp or ignore roll for
|
|
361
|
+
* first-person cameras.
|
|
362
|
+
*
|
|
363
|
+
* @example
|
|
364
|
+
* ```typescript
|
|
365
|
+
* const slightBank: QAngle = { pitch: 0, yaw: 0, roll: 5 };
|
|
366
|
+
* ```
|
|
367
|
+
*/
|
|
368
|
+
roll: number;
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Rotation around the Y axis, in degrees.
|
|
372
|
+
*
|
|
373
|
+
* Positive values typically turn to the right (clockwise when viewed from
|
|
374
|
+
* above) in right-handed systems.
|
|
375
|
+
*
|
|
376
|
+
* @example
|
|
377
|
+
* ```typescript
|
|
378
|
+
* const turnRight: QAngle = { pitch: 0, yaw: 90, roll: 0 };
|
|
379
|
+
* ```
|
|
380
|
+
*/
|
|
381
|
+
yaw: number;
|
|
382
|
+
}
|
|
383
|
+
|
|
322
384
|
/**
|
|
323
385
|
* Represents a memory region with its properties and protection flags.
|
|
324
386
|
*
|
|
@@ -791,3 +853,32 @@ export type Vector3 = {
|
|
|
791
853
|
*/
|
|
792
854
|
z: number;
|
|
793
855
|
};
|
|
856
|
+
|
|
857
|
+
/**
|
|
858
|
+
* Represents a 4D vector with w, x, y, z components.
|
|
859
|
+
*
|
|
860
|
+
* Common use cases:
|
|
861
|
+
* - Homogeneous coordinates (w ≠ 0)
|
|
862
|
+
* - Colors with alpha (x = R, y = G, z = B, w = A)
|
|
863
|
+
* - Packed attributes and shader parameters
|
|
864
|
+
* - As a quaternion carrier when interoperating with APIs expecting {x,y,z,w}
|
|
865
|
+
*
|
|
866
|
+
* Memory layout used by {@link Memory.vector4} is four 32-bit floats stored in
|
|
867
|
+
* the order **x, y, z, w**, while this type exposes `{ w, x, y, z }` for
|
|
868
|
+
* consistency with {@link Quaternion}.
|
|
869
|
+
*
|
|
870
|
+
* @example
|
|
871
|
+
* ```typescript
|
|
872
|
+
* // RGBA color
|
|
873
|
+
* const red: Vector4 = { x: 255, y: 0, z: 0, w: 255 };
|
|
874
|
+
*
|
|
875
|
+
* // Homogeneous point (x, y, z, w)
|
|
876
|
+
* const p: Vector4 = { x: 10, y: 20, z: 30, w: 1 };
|
|
877
|
+
* ```
|
|
878
|
+
*/
|
|
879
|
+
export type Vector4 = {
|
|
880
|
+
w: number;
|
|
881
|
+
x: number;
|
|
882
|
+
y: number;
|
|
883
|
+
z: number;
|
|
884
|
+
};
|