bun-memory 1.1.35 → 1.1.36
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/example/benchmark.ts +71 -51
- package/example/trigger-bot.ts +7 -5
- package/package.json +1 -1
- package/structs/Memory.ts +80 -64
package/example/benchmark.ts
CHANGED
|
@@ -10,6 +10,8 @@ import Memory from 'bun-memory';
|
|
|
10
10
|
import ClientDLLJSON from './offsets/client_dll.json';
|
|
11
11
|
import OffsetsJSON from './offsets/offsets.json';
|
|
12
12
|
|
|
13
|
+
const Iterations = 1e6;
|
|
14
|
+
|
|
13
15
|
// Load the needed offsets as bigints… It's ugly but… IntelliSense! 🫠…
|
|
14
16
|
const Client = {
|
|
15
17
|
...Object.fromEntries(Object.entries(ClientDLLJSON['client.dll'].classes).map(([class_, { fields }]) => [class_, Object.fromEntries(Object.entries(fields).map(([field, value]) => [field, BigInt(value)]))])),
|
|
@@ -32,11 +34,12 @@ if (ClientPtr === undefined) {
|
|
|
32
34
|
// Warmup…
|
|
33
35
|
console.log('Warming up…');
|
|
34
36
|
|
|
35
|
-
for (let i = 0; i <
|
|
37
|
+
for (let i = 0; i < Iterations; i++) {
|
|
36
38
|
const GlobalVarsPtr = cs2.u64(ClientPtr + Client.Other.dwGlobalVars);
|
|
37
39
|
/* */ const CurTime = cs2.f32(GlobalVarsPtr + 0x30n);
|
|
38
40
|
|
|
39
41
|
const lPlayerControllerPtr = cs2.u64(ClientPtr + Client.Other.dwLocalPlayerController);
|
|
42
|
+
/* */ const lPlayerName = cs2.string(lPlayerControllerPtr + Client.CBasePlayerController.m_iszPlayerName, 32);
|
|
40
43
|
|
|
41
44
|
const lPlayerPawnPtr = cs2.u64(ClientPtr + Client.Other.dwLocalPlayerPawn);
|
|
42
45
|
/* */ const lHealth = cs2.u32(lPlayerPawnPtr + Client.C_BaseEntity.m_iHealth);
|
|
@@ -52,75 +55,92 @@ const EntityListScratch = new BigUint64Array(0x200 / 0x08);
|
|
|
52
55
|
const EntityClassInfoNames = new Map<bigint, string>();
|
|
53
56
|
|
|
54
57
|
// Start the test…
|
|
55
|
-
|
|
58
|
+
for (let i = 0; i < 10; i++) {
|
|
59
|
+
console.log('Starting the test…');
|
|
56
60
|
|
|
57
|
-
const
|
|
61
|
+
const start = performance.now();
|
|
58
62
|
|
|
59
|
-
const EntityListPtr = cs2.u64(ClientPtr + Client.Other.dwEntityList);
|
|
63
|
+
const EntityListPtr = cs2.u64(ClientPtr + Client.Other.dwEntityList);
|
|
60
64
|
|
|
61
|
-
for (let
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
+
for (let j = 0; j < Iterations; j++) {
|
|
66
|
+
try {
|
|
67
|
+
// Traverse the entity list and store it in `BaseEntityPtrs`…
|
|
68
|
+
void cs2.read(EntityListPtr + 0x10n, EntityListScratch);
|
|
65
69
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
70
|
+
// Traverse each of the potential 64 entity chunks…
|
|
71
|
+
for (let k = 0; k < 0x40; k++) {
|
|
72
|
+
const EntityChunkPtr = EntityListScratch[k];
|
|
69
73
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
74
|
+
if (EntityChunkPtr === 0n) {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
73
77
|
|
|
74
|
-
|
|
78
|
+
void cs2.read(EntityChunkPtr, EntityChunkScratch);
|
|
75
79
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
const BaseEntityPtr = EntityChunkScratch[l];
|
|
80
|
+
// Traverse each of the potential 512 entities within this chunk…
|
|
81
|
+
for (let l = 0; l < 0x1e00; l += 0x0f) {
|
|
82
|
+
const BaseEntityPtr = EntityChunkScratch[l];
|
|
80
83
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
+
if (BaseEntityPtr === 0n) {
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
84
87
|
|
|
85
|
-
|
|
88
|
+
const EntityClassInfoPtr = EntityChunkScratch[l + 0x01];
|
|
86
89
|
|
|
87
|
-
|
|
90
|
+
let Name = EntityClassInfoNames.get(EntityClassInfoPtr);
|
|
88
91
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
92
|
+
if (Name === undefined) {
|
|
93
|
+
const SchemaClassInfoDataPtr = cs2.u64(EntityClassInfoPtr + 0x30n);
|
|
94
|
+
/* */ const NamePtr = cs2.u64(SchemaClassInfoDataPtr + 0x08n);
|
|
95
|
+
// /* */ Name = cs2.buffer(NamePtr, 0x20).toString();
|
|
96
|
+
/* */ Name = cs2.string(NamePtr, 0x40);
|
|
93
97
|
|
|
94
|
-
|
|
95
|
-
|
|
98
|
+
EntityClassInfoNames.set(EntityClassInfoPtr, Name);
|
|
99
|
+
}
|
|
96
100
|
|
|
97
|
-
|
|
101
|
+
let BaseEntityPtrs_ = BaseEntityPtrs.get(Name);
|
|
98
102
|
|
|
99
|
-
|
|
100
|
-
|
|
103
|
+
if (BaseEntityPtrs_ === undefined) {
|
|
104
|
+
BaseEntityPtrs_ = [];
|
|
101
105
|
|
|
102
|
-
|
|
103
|
-
|
|
106
|
+
BaseEntityPtrs.set(Name, BaseEntityPtrs_);
|
|
107
|
+
}
|
|
104
108
|
|
|
105
|
-
|
|
109
|
+
BaseEntityPtrs_.push(BaseEntityPtr);
|
|
110
|
+
}
|
|
106
111
|
}
|
|
107
|
-
}
|
|
108
112
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
113
|
+
// ! —————————————————————————————————————————————————————————————————————————————————————————————
|
|
114
|
+
// ! YOUR CODE GOES HERE…
|
|
115
|
+
// ! —————————————————————————————————————————————————————————————————————————————————————————————
|
|
116
|
+
|
|
117
|
+
// // Log our entities…
|
|
118
|
+
// console.log(
|
|
119
|
+
// 'Entities found this tick: %O',
|
|
120
|
+
// Object.fromEntries([...BaseEntityPtrs.entries()].map(([Name, { length }]) => [Name, length])) //
|
|
121
|
+
// );
|
|
122
|
+
|
|
123
|
+
// ! —————————————————————————————————————————————————————————————————————————————————————————————
|
|
124
|
+
// ! YOUR CODE ENDS HERE…
|
|
125
|
+
// ! —————————————————————————————————————————————————————————————————————————————————————————————
|
|
126
|
+
} finally {
|
|
127
|
+
// Clear the entity list…
|
|
128
|
+
for (const BaseEntityPtrs_ of BaseEntityPtrs.values()) {
|
|
129
|
+
BaseEntityPtrs_.length = 0;
|
|
130
|
+
}
|
|
120
131
|
}
|
|
121
132
|
}
|
|
122
|
-
}
|
|
123
133
|
|
|
124
|
-
const
|
|
134
|
+
const end = performance.now();
|
|
135
|
+
|
|
136
|
+
const total = end - start;
|
|
137
|
+
const average = total / Iterations;
|
|
125
138
|
|
|
126
|
-
console.log(
|
|
139
|
+
console.log(
|
|
140
|
+
'Completed %d iterations in %ss, averaging %sms (%sµs) each…', //
|
|
141
|
+
Iterations,
|
|
142
|
+
(total / 1_000).toFixed(2),
|
|
143
|
+
average.toFixed(2),
|
|
144
|
+
(average * 1_000).toFixed(2)
|
|
145
|
+
);
|
|
146
|
+
}
|
package/example/trigger-bot.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FFIType, dlopen } from 'bun:ffi';
|
|
1
|
+
import { FFIType, dlopen, ptr } from 'bun:ffi';
|
|
2
2
|
import { sleep } from 'bun';
|
|
3
3
|
|
|
4
4
|
import Memory from 'bun-memory';
|
|
@@ -32,12 +32,14 @@ const Client = {
|
|
|
32
32
|
const cs2 = new Memory('cs2.exe');
|
|
33
33
|
|
|
34
34
|
// Get the base for client.dll…
|
|
35
|
-
const
|
|
35
|
+
const client = cs2.modules['client.dll'];
|
|
36
36
|
|
|
37
|
-
if (
|
|
38
|
-
throw new TypeError('
|
|
37
|
+
if (client === undefined) {
|
|
38
|
+
throw new TypeError('client must not be undefined.');
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
const ClientPtr = client.base;
|
|
42
|
+
|
|
41
43
|
// Create a cache for class name strings… 🫠…
|
|
42
44
|
const Cache_Names = new Map<bigint, string>();
|
|
43
45
|
|
|
@@ -97,7 +99,7 @@ async function tick(ClientPtr: bigint) {
|
|
|
97
99
|
if (Name === undefined) {
|
|
98
100
|
const SchemaClassInfoDataPtr = cs2.u64(EntityClassInfoPtr + 0x30n);
|
|
99
101
|
/* */ const NamePtr = cs2.u64(SchemaClassInfoDataPtr + 0x08n);
|
|
100
|
-
/* */ Name = cs2.
|
|
102
|
+
/* */ Name = cs2.string(NamePtr, 0x80);
|
|
101
103
|
|
|
102
104
|
Cache_Names.set(EntityClassInfoPtr, Name);
|
|
103
105
|
}
|
package/package.json
CHANGED
package/structs/Memory.ts
CHANGED
|
@@ -7,7 +7,10 @@ const {
|
|
|
7
7
|
symbols: { CloseHandle, CreateToolhelp32Snapshot, GetLastError, Module32FirstW, Module32NextW, OpenProcess, Process32FirstW, Process32NextW, ReadProcessMemory, VirtualQueryEx, WriteProcessMemory },
|
|
8
8
|
} = dlopen('kernel32.dll', {
|
|
9
9
|
CloseHandle: { args: [FFIType.u64], returns: FFIType.bool },
|
|
10
|
+
CreateRemoteThread: { args: [FFIType.u64, FFIType.u64, FFIType.u64, FFIType.u64, FFIType.u64, FFIType.u32, FFIType.ptr], returns: FFIType.u64 },
|
|
10
11
|
CreateToolhelp32Snapshot: { args: [FFIType.u32, FFIType.u32], returns: FFIType.u64 },
|
|
12
|
+
GetCurrentProcess: { args: [], returns: FFIType.ptr },
|
|
13
|
+
GetExitCodeThread: { args: [FFIType.u64, FFIType.ptr], returns: FFIType.bool },
|
|
11
14
|
GetLastError: { returns: FFIType.u32 },
|
|
12
15
|
IsWow64Process2: { args: [FFIType.u64, FFIType.ptr, FFIType.ptr], returns: FFIType.bool },
|
|
13
16
|
Module32FirstW: { args: [FFIType.u64, FFIType.ptr], returns: FFIType.bool },
|
|
@@ -16,8 +19,11 @@ const {
|
|
|
16
19
|
Process32FirstW: { args: [FFIType.u64, FFIType.ptr], returns: FFIType.bool },
|
|
17
20
|
Process32NextW: { args: [FFIType.u64, FFIType.ptr], returns: FFIType.bool },
|
|
18
21
|
ReadProcessMemory: { args: [FFIType.u64, FFIType.u64, FFIType.ptr, FFIType.u64_fast, FFIType.ptr], returns: FFIType.bool },
|
|
22
|
+
VirtualAllocEx: { args: [FFIType.u64, FFIType.u64, FFIType.u64, FFIType.u32, FFIType.u32], returns: FFIType.u64 },
|
|
23
|
+
VirtualFreeEx: { args: [FFIType.u64, FFIType.u64, FFIType.u64, FFIType.u32], returns: FFIType.bool },
|
|
19
24
|
VirtualProtectEx: { args: [FFIType.u64, FFIType.u64, FFIType.u64, FFIType.u32, FFIType.ptr], returns: FFIType.bool },
|
|
20
25
|
VirtualQueryEx: { args: [FFIType.u64, FFIType.u64, FFIType.ptr, FFIType.u64], returns: FFIType.u64 },
|
|
26
|
+
WaitForSingleObject: { args: [FFIType.u64, FFIType.u32], returns: FFIType.u32 },
|
|
21
27
|
WriteProcessMemory: { args: [FFIType.u64, FFIType.u64, FFIType.ptr, FFIType.u64_fast, FFIType.ptr], returns: FFIType.bool },
|
|
22
28
|
});
|
|
23
29
|
|
|
@@ -28,6 +34,7 @@ const {
|
|
|
28
34
|
*
|
|
29
35
|
* Many scalar reads utilize `TypedArray` scratches to avoid a second FFI hop, such as calling `bun:ffi.read.*`.
|
|
30
36
|
*
|
|
37
|
+
* @todo Add call method for calling functions in remote process.
|
|
31
38
|
* @todo Add support for 32 or 64-bit processes using IsWow64Process2 (Windows 10+).
|
|
32
39
|
* @todo When adding 32-bit support, several u64 will need changed to u64_fast.
|
|
33
40
|
*
|
|
@@ -109,6 +116,8 @@ class Memory {
|
|
|
109
116
|
throw new Error(`Process not found: ${identifier}…`);
|
|
110
117
|
}
|
|
111
118
|
|
|
119
|
+
// public call(address: bigint, args: { type: FFIType, value: any }[] = [], timeout: number = 5_000): bigint {}
|
|
120
|
+
|
|
112
121
|
/**
|
|
113
122
|
* Memory protection flags for safe and unsafe regions.
|
|
114
123
|
* Used to filter readable/writable memory areas.
|
|
@@ -171,9 +180,10 @@ class Memory {
|
|
|
171
180
|
private readonly ScratchMemoryBasicInformation = Buffer.allocUnsafe(0x30 /* sizeof(MEMORY_BASIC_INFORMATION) */);
|
|
172
181
|
private readonly ScratchModuleEntry32W = Buffer.allocUnsafe(0x438 /* sizeof(MODULEENTRY32W) */);
|
|
173
182
|
|
|
174
|
-
private static TextDecoderUTF16 = new TextDecoder('utf-16');
|
|
175
183
|
private static TextDecoderUTF8 = new TextDecoder('utf-8');
|
|
176
184
|
|
|
185
|
+
private static TextEncoderUTF8 = new TextEncoder('utf-8');
|
|
186
|
+
|
|
177
187
|
private readonly hProcess: bigint;
|
|
178
188
|
private readonly th32ProcessID: number;
|
|
179
189
|
|
|
@@ -190,43 +200,6 @@ class Memory {
|
|
|
190
200
|
return this._modules;
|
|
191
201
|
}
|
|
192
202
|
|
|
193
|
-
/**
|
|
194
|
-
* Returns memory regions in a given address range.
|
|
195
|
-
* @param address Start address.
|
|
196
|
-
* @param length Number of bytes to scan.
|
|
197
|
-
* @returns Array of memory regions.
|
|
198
|
-
*/
|
|
199
|
-
private regions(address: bigint, length: bigint | number): Region[] {
|
|
200
|
-
const dwLength = 0x30; /* sizeof(MEMORY_BASIC_INFORMATION) */
|
|
201
|
-
let lpAddress = BigInt(address); // prettier-ignore
|
|
202
|
-
const lpBuffer = this.ScratchMemoryBasicInformation;
|
|
203
|
-
|
|
204
|
-
const bVirtualQueryEx = !!VirtualQueryEx(this.hProcess, lpAddress, lpBuffer, dwLength);
|
|
205
|
-
|
|
206
|
-
if (!bVirtualQueryEx) {
|
|
207
|
-
throw new Win32Error('VirtualQueryEx', GetLastError());
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
const end = lpAddress + BigInt(length);
|
|
211
|
-
const result: Region[] = [];
|
|
212
|
-
|
|
213
|
-
do {
|
|
214
|
-
const baseAddress = lpBuffer.readBigUInt64LE();
|
|
215
|
-
const protect = lpBuffer.readUInt32LE(36);
|
|
216
|
-
const regionSize = lpBuffer.readBigUInt64LE(24);
|
|
217
|
-
const state = lpBuffer.readUInt32LE(32);
|
|
218
|
-
const type = lpBuffer.readUInt32LE(40);
|
|
219
|
-
|
|
220
|
-
if ((protect & Memory.MemoryProtections.Safe) !== 0 && (protect & Memory.MemoryProtections.Unsafe) === 0 && state === 0x1000 /* MEM_COMMIT */) {
|
|
221
|
-
result.push({ base: baseAddress, protect, size: regionSize, state, type });
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
lpAddress = baseAddress + regionSize;
|
|
225
|
-
} while (lpAddress < end && !!VirtualQueryEx(this.hProcess, lpAddress, lpBuffer, dwLength));
|
|
226
|
-
|
|
227
|
-
return result;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
203
|
/**
|
|
231
204
|
* Closes the process handle.
|
|
232
205
|
* @example
|
|
@@ -447,7 +420,13 @@ class Memory {
|
|
|
447
420
|
if (typeof lengthOrValue === 'number') {
|
|
448
421
|
const scratch = new Uint8Array(lengthOrValue);
|
|
449
422
|
|
|
450
|
-
this.read(address, scratch);
|
|
423
|
+
void this.read(address, scratch);
|
|
424
|
+
|
|
425
|
+
const indexOf = scratch.indexOf(0x00);
|
|
426
|
+
|
|
427
|
+
if (indexOf === -1) {
|
|
428
|
+
scratch[lengthOrValue - 1] = 0x00;
|
|
429
|
+
}
|
|
451
430
|
|
|
452
431
|
return new CString(scratch.ptr);
|
|
453
432
|
}
|
|
@@ -506,7 +485,7 @@ class Memory {
|
|
|
506
485
|
const length = lengthOrValues;
|
|
507
486
|
const scratch = new Float32Array(length);
|
|
508
487
|
|
|
509
|
-
this.read(address, scratch);
|
|
488
|
+
void this.read(address, scratch);
|
|
510
489
|
|
|
511
490
|
return scratch;
|
|
512
491
|
}
|
|
@@ -565,7 +544,7 @@ class Memory {
|
|
|
565
544
|
const length = lengthOrValues;
|
|
566
545
|
const scratch = new Float64Array(length);
|
|
567
546
|
|
|
568
|
-
this.read(address, scratch);
|
|
547
|
+
void this.read(address, scratch);
|
|
569
548
|
|
|
570
549
|
return scratch;
|
|
571
550
|
}
|
|
@@ -624,7 +603,7 @@ class Memory {
|
|
|
624
603
|
const length = lengthOrValues;
|
|
625
604
|
const scratch = new Int16Array(length);
|
|
626
605
|
|
|
627
|
-
this.read(address, scratch);
|
|
606
|
+
void this.read(address, scratch);
|
|
628
607
|
|
|
629
608
|
return scratch;
|
|
630
609
|
}
|
|
@@ -683,7 +662,7 @@ class Memory {
|
|
|
683
662
|
const length = lengthOrValues;
|
|
684
663
|
const scratch = new Int32Array(length);
|
|
685
664
|
|
|
686
|
-
this.read(address, scratch);
|
|
665
|
+
void this.read(address, scratch);
|
|
687
666
|
|
|
688
667
|
return scratch;
|
|
689
668
|
}
|
|
@@ -742,7 +721,7 @@ class Memory {
|
|
|
742
721
|
const length = lengthOrValues;
|
|
743
722
|
const scratch = new BigInt64Array(length);
|
|
744
723
|
|
|
745
|
-
this.read(address, scratch);
|
|
724
|
+
void this.read(address, scratch);
|
|
746
725
|
|
|
747
726
|
return scratch;
|
|
748
727
|
}
|
|
@@ -801,7 +780,7 @@ class Memory {
|
|
|
801
780
|
const length = lengthOrValues;
|
|
802
781
|
const scratch = new Int8Array(length);
|
|
803
782
|
|
|
804
|
-
this.read(address, scratch);
|
|
783
|
+
void this.read(address, scratch);
|
|
805
784
|
|
|
806
785
|
return scratch;
|
|
807
786
|
}
|
|
@@ -831,7 +810,7 @@ class Memory {
|
|
|
831
810
|
if (values === undefined) {
|
|
832
811
|
const scratch = new Float32Array(0x09);
|
|
833
812
|
|
|
834
|
-
this.read(address, scratch);
|
|
813
|
+
void this.read(address, scratch);
|
|
835
814
|
|
|
836
815
|
return scratch;
|
|
837
816
|
}
|
|
@@ -863,7 +842,7 @@ class Memory {
|
|
|
863
842
|
if (values === undefined) {
|
|
864
843
|
const scratch = new Float32Array(0x0c);
|
|
865
844
|
|
|
866
|
-
this.read(address, scratch);
|
|
845
|
+
void this.read(address, scratch);
|
|
867
846
|
|
|
868
847
|
return scratch;
|
|
869
848
|
}
|
|
@@ -895,7 +874,7 @@ class Memory {
|
|
|
895
874
|
if (values === undefined) {
|
|
896
875
|
const scratch = new Float32Array(0x10);
|
|
897
876
|
|
|
898
|
-
this.read(address, scratch);
|
|
877
|
+
void this.read(address, scratch);
|
|
899
878
|
|
|
900
879
|
return scratch;
|
|
901
880
|
}
|
|
@@ -931,7 +910,7 @@ class Memory {
|
|
|
931
910
|
|
|
932
911
|
const scratch = new Uint32Array(size);
|
|
933
912
|
|
|
934
|
-
this.read(elementsPtr, scratch);
|
|
913
|
+
void this.read(elementsPtr, scratch);
|
|
935
914
|
|
|
936
915
|
return scratch;
|
|
937
916
|
}
|
|
@@ -961,7 +940,7 @@ class Memory {
|
|
|
961
940
|
const Scratch8Float32Array = this.Scratch8Float32Array;
|
|
962
941
|
|
|
963
942
|
if (value === undefined) {
|
|
964
|
-
this.read(address, Scratch8Float32Array);
|
|
943
|
+
void this.read(address, Scratch8Float32Array);
|
|
965
944
|
|
|
966
945
|
const x = Scratch8Float32Array[0x00],
|
|
967
946
|
y = Scratch8Float32Array[0x01]; // prettier-ignore
|
|
@@ -996,7 +975,7 @@ class Memory {
|
|
|
996
975
|
const length = lengthOrValues;
|
|
997
976
|
const scratch = new Float32Array(length * 2);
|
|
998
977
|
|
|
999
|
-
this.read(address, scratch);
|
|
978
|
+
void this.read(address, scratch);
|
|
1000
979
|
|
|
1001
980
|
const result = new Array<Vector2>(length);
|
|
1002
981
|
|
|
@@ -1059,7 +1038,7 @@ class Memory {
|
|
|
1059
1038
|
const Scratch12Float32Array = this.Scratch12Float32Array;
|
|
1060
1039
|
|
|
1061
1040
|
if (value === undefined) {
|
|
1062
|
-
this.read(address, Scratch12Float32Array);
|
|
1041
|
+
void this.read(address, Scratch12Float32Array);
|
|
1063
1042
|
|
|
1064
1043
|
const pitch = Scratch12Float32Array[0x00],
|
|
1065
1044
|
roll = Scratch12Float32Array[0x02],
|
|
@@ -1096,7 +1075,7 @@ class Memory {
|
|
|
1096
1075
|
const length = lengthOrValues;
|
|
1097
1076
|
const scratch = new Float32Array(length * 0x03);
|
|
1098
1077
|
|
|
1099
|
-
this.read(address, scratch);
|
|
1078
|
+
void this.read(address, scratch);
|
|
1100
1079
|
|
|
1101
1080
|
const result = new Array<QAngle>(length);
|
|
1102
1081
|
|
|
@@ -1173,7 +1152,7 @@ class Memory {
|
|
|
1173
1152
|
const Scratch16Float32Array = this.Scratch16Float32Array;
|
|
1174
1153
|
|
|
1175
1154
|
if (value === undefined) {
|
|
1176
|
-
this.read(address, Scratch16Float32Array);
|
|
1155
|
+
void this.read(address, Scratch16Float32Array);
|
|
1177
1156
|
|
|
1178
1157
|
const w = Scratch16Float32Array[0x03],
|
|
1179
1158
|
x = Scratch16Float32Array[0x00],
|
|
@@ -1212,7 +1191,7 @@ class Memory {
|
|
|
1212
1191
|
const length = lengthOrValues;
|
|
1213
1192
|
const scratch = new Float32Array(length * 0x04); // 4 * f32 per Quaternion
|
|
1214
1193
|
|
|
1215
|
-
this.read(address, scratch);
|
|
1194
|
+
void this.read(address, scratch);
|
|
1216
1195
|
|
|
1217
1196
|
const result = new Array<Quaternion>(length);
|
|
1218
1197
|
|
|
@@ -1291,7 +1270,7 @@ class Memory {
|
|
|
1291
1270
|
const Scratch3 = this.Scratch3;
|
|
1292
1271
|
|
|
1293
1272
|
if (value === undefined) {
|
|
1294
|
-
this.read(address, Scratch3);
|
|
1273
|
+
void this.read(address, Scratch3);
|
|
1295
1274
|
|
|
1296
1275
|
const r = Scratch3[0x00],
|
|
1297
1276
|
g = Scratch3[0x01],
|
|
@@ -1353,7 +1332,7 @@ class Memory {
|
|
|
1353
1332
|
const Scratch4 = this.Scratch4;
|
|
1354
1333
|
|
|
1355
1334
|
if (value === undefined) {
|
|
1356
|
-
this.read(address, Scratch4);
|
|
1335
|
+
void this.read(address, Scratch4);
|
|
1357
1336
|
|
|
1358
1337
|
const r = Scratch4[0x00],
|
|
1359
1338
|
g = Scratch4[0x01],
|
|
@@ -1399,6 +1378,43 @@ class Memory {
|
|
|
1399
1378
|
return this;
|
|
1400
1379
|
}
|
|
1401
1380
|
|
|
1381
|
+
/**
|
|
1382
|
+
* Reads or writes a UTF-8 string.
|
|
1383
|
+
* @param address Address to access.
|
|
1384
|
+
* @param lengthOrValue Length to read or string to write.
|
|
1385
|
+
* @returns The string at address, or this instance if writing.
|
|
1386
|
+
* @notice When writing, remember to null-terminate your string (e.g., 'hello\0').
|
|
1387
|
+
* @example
|
|
1388
|
+
* ```ts
|
|
1389
|
+
* const cs2 = new Memory('cs2.exe');
|
|
1390
|
+
* const myString = cs2.string(0x12345678n, 16);
|
|
1391
|
+
* cs2.string(0x12345678n, 'hello\0');
|
|
1392
|
+
* ```
|
|
1393
|
+
*/
|
|
1394
|
+
public string(address: bigint, length: number): string;
|
|
1395
|
+
public string(address: bigint, value: string): this;
|
|
1396
|
+
public string(address: bigint, lengthOrValue: number | string): string | this {
|
|
1397
|
+
if (typeof lengthOrValue === 'number') {
|
|
1398
|
+
const scratch = new Uint8Array(lengthOrValue);
|
|
1399
|
+
|
|
1400
|
+
void this.read(address, scratch);
|
|
1401
|
+
|
|
1402
|
+
const indexOf = scratch.indexOf(0x00);
|
|
1403
|
+
|
|
1404
|
+
return Memory.TextDecoderUTF8.decode(
|
|
1405
|
+
scratch.subarray(0, indexOf !== -1 ? indexOf : lengthOrValue) //
|
|
1406
|
+
);
|
|
1407
|
+
|
|
1408
|
+
// return new CString(scratch.ptr).valueOf();
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
const scratch = Memory.TextEncoderUTF8.encode(lengthOrValue);
|
|
1412
|
+
|
|
1413
|
+
this.write(address, scratch);
|
|
1414
|
+
|
|
1415
|
+
return this;
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1402
1418
|
/**
|
|
1403
1419
|
* Reads or writes a 16-bit unsigned integer.
|
|
1404
1420
|
* @param address Address to access.
|
|
@@ -1446,7 +1462,7 @@ class Memory {
|
|
|
1446
1462
|
const length = lengthOrValues;
|
|
1447
1463
|
const scratch = new Uint16Array(length);
|
|
1448
1464
|
|
|
1449
|
-
this.read(address, scratch);
|
|
1465
|
+
void this.read(address, scratch);
|
|
1450
1466
|
|
|
1451
1467
|
return scratch;
|
|
1452
1468
|
}
|
|
@@ -1505,7 +1521,7 @@ class Memory {
|
|
|
1505
1521
|
const length = lengthOrValues;
|
|
1506
1522
|
const scratch = new Uint32Array(length);
|
|
1507
1523
|
|
|
1508
|
-
this.read(address, scratch);
|
|
1524
|
+
void this.read(address, scratch);
|
|
1509
1525
|
|
|
1510
1526
|
return scratch;
|
|
1511
1527
|
}
|
|
@@ -1564,7 +1580,7 @@ class Memory {
|
|
|
1564
1580
|
const length = lengthOrValues;
|
|
1565
1581
|
const scratch = new BigUint64Array(length);
|
|
1566
1582
|
|
|
1567
|
-
this.read(address, scratch);
|
|
1583
|
+
void this.read(address, scratch);
|
|
1568
1584
|
|
|
1569
1585
|
return scratch;
|
|
1570
1586
|
}
|
|
@@ -1623,7 +1639,7 @@ class Memory {
|
|
|
1623
1639
|
const length = lengthOrValues;
|
|
1624
1640
|
const scratch = new Uint8Array(length);
|
|
1625
1641
|
|
|
1626
|
-
this.read(address, scratch);
|
|
1642
|
+
void this.read(address, scratch);
|
|
1627
1643
|
|
|
1628
1644
|
return scratch;
|
|
1629
1645
|
}
|
|
@@ -1761,7 +1777,7 @@ class Memory {
|
|
|
1761
1777
|
const Scratch12Float32Array = this.Scratch12Float32Array;
|
|
1762
1778
|
|
|
1763
1779
|
if (value === undefined) {
|
|
1764
|
-
this.read(address, Scratch12Float32Array);
|
|
1780
|
+
void this.read(address, Scratch12Float32Array);
|
|
1765
1781
|
|
|
1766
1782
|
const x = Scratch12Float32Array[0x00],
|
|
1767
1783
|
y = Scratch12Float32Array[0x01],
|
|
@@ -1798,7 +1814,7 @@ class Memory {
|
|
|
1798
1814
|
const length = lengthOrValues;
|
|
1799
1815
|
const scratch = new Float32Array(length * 0x03);
|
|
1800
1816
|
|
|
1801
|
-
this.read(address, scratch);
|
|
1817
|
+
void this.read(address, scratch);
|
|
1802
1818
|
|
|
1803
1819
|
const result = new Array<Vector3>(length);
|
|
1804
1820
|
|
|
@@ -1964,7 +1980,7 @@ class Memory {
|
|
|
1964
1980
|
? Buffer.from(needle.buffer, needle.byteOffset, needle.byteLength)
|
|
1965
1981
|
: Buffer.from(needle);
|
|
1966
1982
|
|
|
1967
|
-
this.read(address, haystack);
|
|
1983
|
+
void this.read(address, haystack);
|
|
1968
1984
|
|
|
1969
1985
|
if (!all) {
|
|
1970
1986
|
const indexOf = haystack.indexOf(needleBuffer);
|