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.
@@ -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 < 1e6; 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
- console.log('Starting the test…');
58
+ for (let i = 0; i < 10; i++) {
59
+ console.log('Starting the test…');
56
60
 
57
- const performance1 = performance.now();
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 i = 0; i < 1e6; i++) {
62
- try {
63
- // Traverse the entity list and store it in `BaseEntityPtrs`…
64
- cs2.read(EntityListPtr + 0x10n, EntityListScratch);
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
- // Traverse each of the potential 64 entity chunks…
67
- for (let i = 0; i < 0x40; i++) {
68
- const EntityChunkPtr = EntityListScratch[i];
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
- if (EntityChunkPtr === 0n) {
71
- continue;
72
- }
74
+ if (EntityChunkPtr === 0n) {
75
+ continue;
76
+ }
73
77
 
74
- cs2.read(EntityChunkPtr, EntityChunkScratch);
78
+ void cs2.read(EntityChunkPtr, EntityChunkScratch);
75
79
 
76
- // Traverse each of the potential 512 entities within this chunk…
77
- // for (let j = 0, l = 0; j < 0x200; j++, l += 0x0f) {
78
- for (let l = 0; l < 0x1e00; l += 0x0f) {
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
- if (BaseEntityPtr === 0n) {
82
- continue;
83
- }
84
+ if (BaseEntityPtr === 0n) {
85
+ continue;
86
+ }
84
87
 
85
- const EntityClassInfoPtr = EntityChunkScratch[l + 0x01];
88
+ const EntityClassInfoPtr = EntityChunkScratch[l + 0x01];
86
89
 
87
- let Name = EntityClassInfoNames.get(EntityClassInfoPtr);
90
+ let Name = EntityClassInfoNames.get(EntityClassInfoPtr);
88
91
 
89
- if (Name === undefined) {
90
- const SchemaClassInfoDataPtr = cs2.u64(EntityClassInfoPtr + 0x30n);
91
- /* */ const NamePtr = cs2.u64(SchemaClassInfoDataPtr + 0x08n);
92
- /* */ Name = cs2.buffer(NamePtr, 0x20).toString();
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
- EntityClassInfoNames.set(EntityClassInfoPtr, Name);
95
- }
98
+ EntityClassInfoNames.set(EntityClassInfoPtr, Name);
99
+ }
96
100
 
97
- let BaseEntityPtrs_ = BaseEntityPtrs.get(Name);
101
+ let BaseEntityPtrs_ = BaseEntityPtrs.get(Name);
98
102
 
99
- if (BaseEntityPtrs_ === undefined) {
100
- BaseEntityPtrs_ = [];
103
+ if (BaseEntityPtrs_ === undefined) {
104
+ BaseEntityPtrs_ = [];
101
105
 
102
- BaseEntityPtrs.set(Name, BaseEntityPtrs_);
103
- }
106
+ BaseEntityPtrs.set(Name, BaseEntityPtrs_);
107
+ }
104
108
 
105
- BaseEntityPtrs_.push(BaseEntityPtr);
109
+ BaseEntityPtrs_.push(BaseEntityPtr);
110
+ }
106
111
  }
107
- }
108
112
 
109
- // ! —————————————————————————————————————————————————————————————————————————————————————————————
110
- // ! YOUR CODE GOES HERE…
111
- // ! —————————————————————————————————————————————————————————————————————————————————————————————
112
-
113
- // ! —————————————————————————————————————————————————————————————————————————————————————————————
114
- // ! YOUR CODE ENDS HERE…
115
- // ! —————————————————————————————————————————————————————————————————————————————————————————————
116
- } finally {
117
- // Clear the entity list…
118
- for (const BaseEntityPtrs_ of BaseEntityPtrs.values()) {
119
- BaseEntityPtrs_.length = 0;
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 performance2 = performance.now();
134
+ const end = performance.now();
135
+
136
+ const total = end - start;
137
+ const average = total / Iterations;
125
138
 
126
- console.log('Test completed in %fms…', (performance2 - performance1).toFixed(2));
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
+ }
@@ -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 ClientPtr = cs2.modules['client.dll']?.base;
35
+ const client = cs2.modules['client.dll'];
36
36
 
37
- if (ClientPtr === undefined) {
38
- throw new TypeError('ClientPtr must not be undefined.');
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.cString(NamePtr, 0x80).toString();
102
+ /* */ Name = cs2.string(NamePtr, 0x80);
101
103
 
102
104
  Cache_Names.set(EntityClassInfoPtr, Name);
103
105
  }
package/package.json CHANGED
@@ -22,7 +22,7 @@
22
22
  "url": "git://github.com/obscuritysrl/bun-memory.git"
23
23
  },
24
24
  "type": "module",
25
- "version": "1.1.35",
25
+ "version": "1.1.36",
26
26
  "main": "./index.ts",
27
27
  "keywords": [
28
28
  "bun",
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);