bun-memory 1.1.36 → 1.1.38

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/structs/Memory.ts CHANGED
@@ -4,27 +4,21 @@ import type { Module, NetworkUtlVector, Point, QAngle, Quaternion, Region, RGB,
4
4
  import Win32Error from './Win32Error';
5
5
 
6
6
  const {
7
- symbols: { CloseHandle, CreateToolhelp32Snapshot, GetLastError, Module32FirstW, Module32NextW, OpenProcess, Process32FirstW, Process32NextW, ReadProcessMemory, VirtualQueryEx, WriteProcessMemory },
7
+ symbols: { CloseHandle, CreateToolhelp32Snapshot, GetLastError, Module32FirstW, Module32NextW, OpenProcess, Process32FirstW, Process32NextW, ReadProcessMemory, VirtualProtectEx, 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 },
11
10
  CreateToolhelp32Snapshot: { args: [FFIType.u32, FFIType.u32], returns: FFIType.u64 },
12
11
  GetCurrentProcess: { args: [], returns: FFIType.ptr },
13
- GetExitCodeThread: { args: [FFIType.u64, FFIType.ptr], returns: FFIType.bool },
14
12
  GetLastError: { returns: FFIType.u32 },
15
- IsWow64Process2: { args: [FFIType.u64, FFIType.ptr, FFIType.ptr], returns: FFIType.bool },
16
13
  Module32FirstW: { args: [FFIType.u64, FFIType.ptr], returns: FFIType.bool },
17
14
  Module32NextW: { args: [FFIType.u64, FFIType.ptr], returns: FFIType.bool },
18
15
  OpenProcess: { args: [FFIType.u32, FFIType.bool, FFIType.u32], returns: FFIType.u64 },
19
16
  Process32FirstW: { args: [FFIType.u64, FFIType.ptr], returns: FFIType.bool },
20
17
  Process32NextW: { args: [FFIType.u64, FFIType.ptr], returns: FFIType.bool },
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 },
18
+ ReadProcessMemory: { args: [FFIType.u64, FFIType.u64, FFIType.ptr, FFIType.u64, FFIType.ptr], returns: FFIType.bool },
24
19
  VirtualProtectEx: { args: [FFIType.u64, FFIType.u64, FFIType.u64, FFIType.u32, FFIType.ptr], returns: FFIType.bool },
25
20
  VirtualQueryEx: { args: [FFIType.u64, FFIType.u64, FFIType.ptr, FFIType.u64], returns: FFIType.u64 },
26
- WaitForSingleObject: { args: [FFIType.u64, FFIType.u32], returns: FFIType.u32 },
27
- WriteProcessMemory: { args: [FFIType.u64, FFIType.u64, FFIType.ptr, FFIType.u64_fast, FFIType.ptr], returns: FFIType.bool },
21
+ WriteProcessMemory: { args: [FFIType.u64, FFIType.u64, FFIType.ptr, FFIType.u64, FFIType.ptr], returns: FFIType.bool },
28
22
  });
29
23
 
30
24
  /**
@@ -116,17 +110,6 @@ class Memory {
116
110
  throw new Error(`Process not found: ${identifier}…`);
117
111
  }
118
112
 
119
- // public call(address: bigint, args: { type: FFIType, value: any }[] = [], timeout: number = 5_000): bigint {}
120
-
121
- /**
122
- * Memory protection flags for safe and unsafe regions.
123
- * Used to filter readable/writable memory areas.
124
- */
125
- private static readonly MemoryProtections = {
126
- Safe: 0x10 /* PAGE_EXECUTE */ | 0x20 /* PAGE_EXECUTE_READ */ | 0x40 /* PAGE_EXECUTE_READWRITE */ | 0x80 /* PAGE_EXECUTE_WRITECOPY */ | 0x02 /* PAGE_READONLY */ | 0x04 /* PAGE_READWRITE */ | 0x08 /* PAGE_WRITECOPY */,
127
- Unsafe: 0x100 /* PAGE_GUARD */ | 0x01 /* PAGE_NOACCESS */,
128
- };
129
-
130
113
  /**
131
114
  * Regex patterns for matching hex strings and wildcards in memory scans.
132
115
  * Used by the pattern method.
@@ -177,7 +160,6 @@ class Memory {
177
160
  private readonly Scratch16 = new Uint8Array(0x10);
178
161
  private readonly Scratch16Float32Array = new Float32Array(this.Scratch16.buffer, this.Scratch16.byteOffset, 0x04);
179
162
 
180
- private readonly ScratchMemoryBasicInformation = Buffer.allocUnsafe(0x30 /* sizeof(MEMORY_BASIC_INFORMATION) */);
181
163
  private readonly ScratchModuleEntry32W = Buffer.allocUnsafe(0x438 /* sizeof(MODULEENTRY32W) */);
182
164
 
183
165
  private static TextDecoderUTF8 = new TextDecoder('utf-8');
@@ -305,7 +287,7 @@ class Memory {
305
287
  public read<T extends Scratch>(address: bigint, scratch: T): T {
306
288
  const lpBaseAddress = address;
307
289
  const lpBuffer = ptr(scratch);
308
- const nSize = scratch.byteLength;
290
+ const nSize = BigInt(scratch.byteLength);
309
291
  const numberOfBytesRead = 0x00n;
310
292
 
311
293
  const bReadProcessMemory = ReadProcessMemory(this.hProcess, lpBaseAddress, lpBuffer, nSize, numberOfBytesRead);
@@ -321,25 +303,57 @@ class Memory {
321
303
  * Writes a buffer to memory.
322
304
  * @param address Address to write to.
323
305
  * @param scratch Buffer to write.
306
+ * @param force When writing, if true temporarily changes page protection to allow the write.
324
307
  * @returns This instance.
325
- * @todo Add a `force: boolean` option that uses `VirtualProtectEx` for a temporary protection change when set to `true`.
326
- * @todo Consider inlining the call in the if to cut a binding… I hate the idea… 🫠…
327
308
  * @example
328
309
  * ```ts
329
310
  * const cs2 = new Memory('cs2.exe');
330
311
  * cs2.write(0x12345678n, new Uint8Array([1,2,3,4]));
312
+ * // Force a write by temporarily changing memory protection
313
+ * cs2.write(0x12345678n, new Uint8Array([1,2,3,4]), true);
331
314
  * ```
332
315
  */
333
- private write(address: bigint, scratch: Scratch): this {
316
+ public write(address: bigint, scratch: Scratch, force: boolean = false): this {
334
317
  const lpBaseAddress = address;
335
318
  const lpBuffer = scratch.ptr;
336
- const nSize = scratch.byteLength;
319
+ const nSize = BigInt(scratch.byteLength);
337
320
  const numberOfBytesWritten = 0x00n;
338
321
 
339
- const bWriteProcessMemory = WriteProcessMemory(this.hProcess, lpBaseAddress, lpBuffer, nSize, numberOfBytesWritten);
322
+ if (!force) {
323
+ const bWriteProcessMemory = WriteProcessMemory(this.hProcess, lpBaseAddress, lpBuffer, nSize, numberOfBytesWritten);
324
+
325
+ if (!bWriteProcessMemory) {
326
+ throw new Win32Error('WriteProcessMemory', GetLastError());
327
+ }
328
+
329
+ return this;
330
+ }
331
+
332
+ const dwSize = nSize;
333
+ const flNewProtect = 0x40; /* PAGE_EXECUTE_READWRITE */
334
+ const lpflOldProtect = Buffer.allocUnsafe(0x04);
335
+
336
+ const bVirtualProtectEx = VirtualProtectEx(this.hProcess, lpBaseAddress, dwSize, flNewProtect, lpflOldProtect.ptr);
340
337
 
341
- if (!bWriteProcessMemory) {
342
- throw new Win32Error('WriteProcessMemory', GetLastError());
338
+ if (!bVirtualProtectEx) {
339
+ throw new Win32Error('VirtualProtectEx', GetLastError());
340
+ }
341
+
342
+ try {
343
+ const bWriteProcessMemory = WriteProcessMemory(this.hProcess, lpBaseAddress, lpBuffer, nSize, numberOfBytesWritten);
344
+
345
+ if (!bWriteProcessMemory) {
346
+ throw new Win32Error('WriteProcessMemory', GetLastError());
347
+ }
348
+ } finally {
349
+ const flNewProtect2 = lpflOldProtect.readUInt32LE(0x00);
350
+ const lpflOldProtect2 = Buffer.allocUnsafe(0x04);
351
+
352
+ const bVirtualProtectEx2 = VirtualProtectEx(this.hProcess, lpBaseAddress, dwSize, flNewProtect2, lpflOldProtect2.ptr);
353
+
354
+ if (!bVirtualProtectEx2) {
355
+ throw new Win32Error('VirtualProtectEx', GetLastError());
356
+ }
343
357
  }
344
358
 
345
359
  return this;
@@ -349,6 +363,7 @@ class Memory {
349
363
  * Reads or writes a boolean value.
350
364
  * @param address Address to access.
351
365
  * @param value Optional value to write.
366
+ * @param force When writing, if true temporarily changes page protection to allow the write.
352
367
  * @returns The boolean at address, or this instance if writing.
353
368
  * @example
354
369
  * ```ts
@@ -358,8 +373,8 @@ class Memory {
358
373
  * ```
359
374
  */
360
375
  public bool(address: bigint): boolean;
361
- public bool(address: bigint, value: boolean): this;
362
- public bool(address: bigint, value?: boolean): boolean | this {
376
+ public bool(address: bigint, value: boolean, force?: boolean): this;
377
+ public bool(address: bigint, value?: boolean, force?: boolean): boolean | this {
363
378
  const Scratch1 = this.Scratch1;
364
379
 
365
380
  if (value === undefined) {
@@ -368,7 +383,7 @@ class Memory {
368
383
 
369
384
  Scratch1[0x00] = value ? 1 : 0;
370
385
 
371
- this.write(address, Scratch1);
386
+ void this.write(address, Scratch1, force);
372
387
 
373
388
  return this;
374
389
  }
@@ -377,6 +392,7 @@ class Memory {
377
392
  * Reads or writes a Buffer.
378
393
  * @param address Address to access.
379
394
  * @param lengthOrValue Length to read or Buffer to write.
395
+ * @param force When writing, if true temporarily changes page protection to allow the write.
380
396
  * @returns Buffer read or this instance if writing.
381
397
  * @example
382
398
  * ```ts
@@ -386,8 +402,8 @@ class Memory {
386
402
  * ```
387
403
  */
388
404
  public buffer(address: bigint, length: number): Buffer;
389
- public buffer(address: bigint, value: Buffer): this;
390
- public buffer(address: bigint, lengthOrValue: number | Buffer): Buffer | this {
405
+ public buffer(address: bigint, value: Buffer, force?: boolean): this;
406
+ public buffer(address: bigint, lengthOrValue: number | Buffer, force?: boolean): Buffer | this {
391
407
  if (typeof lengthOrValue === 'number') {
392
408
  const length = lengthOrValue;
393
409
  const scratch = Buffer.allocUnsafe(length);
@@ -397,7 +413,7 @@ class Memory {
397
413
 
398
414
  const value = lengthOrValue;
399
415
 
400
- this.write(address, value);
416
+ void this.write(address, value, force);
401
417
 
402
418
  return this;
403
419
  }
@@ -406,6 +422,7 @@ class Memory {
406
422
  * Reads or writes a C-style string.
407
423
  * @param address Address to access.
408
424
  * @param lengthOrValue Length to read or CString to write.
425
+ * @param force When writing, if true temporarily changes page protection to allow the write.
409
426
  * @returns CString read or this instance if writing.
410
427
  * @example
411
428
  * ```ts
@@ -415,8 +432,8 @@ class Memory {
415
432
  * ```
416
433
  */
417
434
  public cString(address: bigint, length: number): CString;
418
- public cString(address: bigint, value: CString): this;
419
- public cString(address: bigint, lengthOrValue: number | CString): CString | this {
435
+ public cString(address: bigint, value: CString, force?: boolean): this;
436
+ public cString(address: bigint, lengthOrValue: number | CString, force?: boolean): CString | this {
420
437
  if (typeof lengthOrValue === 'number') {
421
438
  const scratch = new Uint8Array(lengthOrValue);
422
439
 
@@ -433,7 +450,7 @@ class Memory {
433
450
 
434
451
  const scratch = Buffer.from(lengthOrValue);
435
452
 
436
- this.write(address, scratch);
453
+ void this.write(address, scratch, force);
437
454
 
438
455
  return this;
439
456
  }
@@ -442,6 +459,7 @@ class Memory {
442
459
  * Reads or writes a 32-bit float.
443
460
  * @param address Address to access.
444
461
  * @param value Optional value to write.
462
+ * @param force When writing, if true temporarily changes page protection to allow the write.
445
463
  * @returns The float at address, or this instance if writing.
446
464
  * @example
447
465
  * ```ts
@@ -451,8 +469,8 @@ class Memory {
451
469
  * ```
452
470
  */
453
471
  public f32(address: bigint): number;
454
- public f32(address: bigint, value: number): this;
455
- public f32(address: bigint, value?: number): number | this {
472
+ public f32(address: bigint, value: number, force?: boolean): this;
473
+ public f32(address: bigint, value?: number, force?: boolean): number | this {
456
474
  const Scratch4Float32Array = this.Scratch4Float32Array; // prettier-ignore
457
475
 
458
476
  if (value === undefined) {
@@ -461,7 +479,7 @@ class Memory {
461
479
 
462
480
  Scratch4Float32Array[0x00] = value;
463
481
 
464
- this.write(address, Scratch4Float32Array);
482
+ void this.write(address, Scratch4Float32Array, force);
465
483
 
466
484
  return this;
467
485
  }
@@ -470,6 +488,7 @@ class Memory {
470
488
  * Reads or writes a Float32Array.
471
489
  * @param address Address to access.
472
490
  * @param lengthOrValues Length to read or Float32Array to write.
491
+ * @param force When writing, if true temporarily changes page protection to allow the write.
473
492
  * @returns Float32Array read or this instance if writing.
474
493
  * @example
475
494
  * ```ts
@@ -479,8 +498,8 @@ class Memory {
479
498
  * ```
480
499
  */
481
500
  public f32Array(address: bigint, length: number): Float32Array;
482
- public f32Array(address: bigint, values: Float32Array): this;
483
- public f32Array(address: bigint, lengthOrValues: Float32Array | number): Float32Array | this {
501
+ public f32Array(address: bigint, values: Float32Array, force?: boolean): this;
502
+ public f32Array(address: bigint, lengthOrValues: Float32Array | number, force?: boolean): Float32Array | this {
484
503
  if (typeof lengthOrValues === 'number') {
485
504
  const length = lengthOrValues;
486
505
  const scratch = new Float32Array(length);
@@ -492,7 +511,7 @@ class Memory {
492
511
 
493
512
  const values = lengthOrValues;
494
513
 
495
- this.write(address, values);
514
+ void this.write(address, values, force);
496
515
 
497
516
  return this;
498
517
  }
@@ -501,6 +520,7 @@ class Memory {
501
520
  * Reads or writes a 64-bit float.
502
521
  * @param address Address to access.
503
522
  * @param value Optional value to write.
523
+ * @param force When writing, if true temporarily changes page protection to allow the write.
504
524
  * @returns The float at address, or this instance if writing.
505
525
  * @example
506
526
  * ```ts
@@ -510,8 +530,8 @@ class Memory {
510
530
  * ```
511
531
  */
512
532
  public f64(address: bigint): number;
513
- public f64(address: bigint, value: number): this;
514
- public f64(address: bigint, value?: number): number | this {
533
+ public f64(address: bigint, value: number, force?: boolean): this;
534
+ public f64(address: bigint, value?: number, force?: boolean): number | this {
515
535
  const Scratch8Float64Array = this.Scratch8Float64Array; // prettier-ignore
516
536
 
517
537
  if (value === undefined) {
@@ -520,7 +540,7 @@ class Memory {
520
540
 
521
541
  Scratch8Float64Array[0x00] = value;
522
542
 
523
- this.write(address, Scratch8Float64Array);
543
+ void this.write(address, Scratch8Float64Array, force);
524
544
 
525
545
  return this;
526
546
  }
@@ -529,6 +549,7 @@ class Memory {
529
549
  * Reads or writes a Float64Array.
530
550
  * @param address Address to access.
531
551
  * @param lengthOrValues Length to read or Float64Array to write.
552
+ * @param force When writing, if true temporarily changes page protection to allow the write.
532
553
  * @returns Float64Array read or this instance if writing.
533
554
  * @example
534
555
  * ```ts
@@ -538,8 +559,8 @@ class Memory {
538
559
  * ```
539
560
  */
540
561
  public f64Array(address: bigint, length: number): Float64Array;
541
- public f64Array(address: bigint, values: Float64Array): this;
542
- public f64Array(address: bigint, lengthOrValues: Float64Array | number): Float64Array | this {
562
+ public f64Array(address: bigint, values: Float64Array, force?: boolean): this;
563
+ public f64Array(address: bigint, lengthOrValues: Float64Array | number, force?: boolean): Float64Array | this {
543
564
  if (typeof lengthOrValues === 'number') {
544
565
  const length = lengthOrValues;
545
566
  const scratch = new Float64Array(length);
@@ -551,7 +572,7 @@ class Memory {
551
572
 
552
573
  const values = lengthOrValues;
553
574
 
554
- this.write(address, values);
575
+ void this.write(address, values, force);
555
576
 
556
577
  return this;
557
578
  }
@@ -560,6 +581,7 @@ class Memory {
560
581
  * Reads or writes a 16-bit integer.
561
582
  * @param address Address to access.
562
583
  * @param value Optional value to write.
584
+ * @param force When writing, if true temporarily changes page protection to allow the write.
563
585
  * @returns The int at address, or this instance if writing.
564
586
  * @example
565
587
  * ```ts
@@ -569,8 +591,8 @@ class Memory {
569
591
  * ```
570
592
  */
571
593
  public i16(address: bigint): number;
572
- public i16(address: bigint, value: number): this;
573
- public i16(address: bigint, value?: number): number | this {
594
+ public i16(address: bigint, value: number, force?: boolean): this;
595
+ public i16(address: bigint, value?: number, force?: boolean): number | this {
574
596
  const Scratch2Int16Array = this.Scratch2Int16Array; // prettier-ignore
575
597
 
576
598
  if (value === undefined) {
@@ -579,7 +601,7 @@ class Memory {
579
601
 
580
602
  Scratch2Int16Array[0x00] = value;
581
603
 
582
- this.write(address, Scratch2Int16Array);
604
+ void this.write(address, Scratch2Int16Array, force);
583
605
 
584
606
  return this;
585
607
  }
@@ -588,6 +610,7 @@ class Memory {
588
610
  * Reads or writes an Int16Array.
589
611
  * @param address Address to access.
590
612
  * @param lengthOrValues Length to read or Int16Array to write.
613
+ * @param force When writing, if true temporarily changes page protection to allow the write.
591
614
  * @returns Int16Array read or this instance if writing.
592
615
  * @example
593
616
  * ```ts
@@ -597,8 +620,8 @@ class Memory {
597
620
  * ```
598
621
  */
599
622
  public i16Array(address: bigint, length: number): Int16Array;
600
- public i16Array(address: bigint, values: Int16Array): this;
601
- public i16Array(address: bigint, lengthOrValues: Int16Array | number): Int16Array | this {
623
+ public i16Array(address: bigint, values: Int16Array, force?: boolean): this;
624
+ public i16Array(address: bigint, lengthOrValues: Int16Array | number, force?: boolean): Int16Array | this {
602
625
  if (typeof lengthOrValues === 'number') {
603
626
  const length = lengthOrValues;
604
627
  const scratch = new Int16Array(length);
@@ -610,7 +633,7 @@ class Memory {
610
633
 
611
634
  const values = lengthOrValues;
612
635
 
613
- this.write(address, values);
636
+ void this.write(address, values, force);
614
637
 
615
638
  return this;
616
639
  }
@@ -619,6 +642,7 @@ class Memory {
619
642
  * Reads or writes a 32-bit integer.
620
643
  * @param address Address to access.
621
644
  * @param value Optional value to write.
645
+ * @param force When writing, if true temporarily changes page protection to allow the write.
622
646
  * @returns The int at address, or this instance if writing.
623
647
  * @example
624
648
  * ```ts
@@ -628,8 +652,8 @@ class Memory {
628
652
  * ```
629
653
  */
630
654
  public i32(address: bigint): number;
631
- public i32(address: bigint, value: number): this;
632
- public i32(address: bigint, value?: number): number | this {
655
+ public i32(address: bigint, value: number, force?: boolean): this;
656
+ public i32(address: bigint, value?: number, force?: boolean): number | this {
633
657
  const Scratch4Int32Array = this.Scratch4Int32Array;
634
658
 
635
659
  if (value === undefined) {
@@ -638,7 +662,7 @@ class Memory {
638
662
 
639
663
  Scratch4Int32Array[0x00] = value;
640
664
 
641
- this.write(address, Scratch4Int32Array);
665
+ void this.write(address, Scratch4Int32Array, force);
642
666
 
643
667
  return this;
644
668
  }
@@ -647,6 +671,7 @@ class Memory {
647
671
  * Reads or writes an Int32Array.
648
672
  * @param address Address to access.
649
673
  * @param lengthOrValues Length to read or Int32Array to write.
674
+ * @param force When writing, if true temporarily changes page protection to allow the write.
650
675
  * @returns Int32Array read or this instance if writing.
651
676
  * @example
652
677
  * ```ts
@@ -656,8 +681,8 @@ class Memory {
656
681
  * ```
657
682
  */
658
683
  public i32Array(address: bigint, length: number): Int32Array;
659
- public i32Array(address: bigint, values: Int32Array): this;
660
- public i32Array(address: bigint, lengthOrValues: Int32Array | number): Int32Array | this {
684
+ public i32Array(address: bigint, values: Int32Array, force?: boolean): this;
685
+ public i32Array(address: bigint, lengthOrValues: Int32Array | number, force?: boolean): Int32Array | this {
661
686
  if (typeof lengthOrValues === 'number') {
662
687
  const length = lengthOrValues;
663
688
  const scratch = new Int32Array(length);
@@ -669,7 +694,7 @@ class Memory {
669
694
 
670
695
  const values = lengthOrValues;
671
696
 
672
- this.write(address, values);
697
+ void this.write(address, values, force);
673
698
 
674
699
  return this;
675
700
  }
@@ -678,6 +703,7 @@ class Memory {
678
703
  * Reads or writes a 64-bit integer.
679
704
  * @param address Address to access.
680
705
  * @param value Optional value to write.
706
+ * @param force When writing, if true temporarily changes page protection to allow the write.
681
707
  * @returns The bigint at address, or this instance if writing.
682
708
  * @example
683
709
  * ```ts
@@ -687,8 +713,8 @@ class Memory {
687
713
  * ```
688
714
  */
689
715
  public i64(address: bigint): bigint;
690
- public i64(address: bigint, value: bigint): this;
691
- public i64(address: bigint, value?: bigint): bigint | this {
716
+ public i64(address: bigint, value: bigint, force?: boolean): this;
717
+ public i64(address: bigint, value?: bigint, force?: boolean): bigint | this {
692
718
  const Scratch8BigInt64Array = this.Scratch8BigInt64Array;
693
719
 
694
720
  if (value === undefined) {
@@ -697,7 +723,7 @@ class Memory {
697
723
 
698
724
  Scratch8BigInt64Array[0x00] = value;
699
725
 
700
- this.write(address, Scratch8BigInt64Array);
726
+ void this.write(address, Scratch8BigInt64Array, force);
701
727
 
702
728
  return this;
703
729
  }
@@ -706,6 +732,7 @@ class Memory {
706
732
  * Reads or writes a BigInt64Array.
707
733
  * @param address Address to access.
708
734
  * @param lengthOrValues Length to read or BigInt64Array to write.
735
+ * @param force When writing, if true temporarily changes page protection to allow the write.
709
736
  * @returns BigInt64Array read or this instance if writing.
710
737
  * @example
711
738
  * ```ts
@@ -715,8 +742,8 @@ class Memory {
715
742
  * ```
716
743
  */
717
744
  public i64Array(address: bigint, length: number): BigInt64Array;
718
- public i64Array(address: bigint, values: BigInt64Array): this;
719
- public i64Array(address: bigint, lengthOrValues: BigInt64Array | number): BigInt64Array | this {
745
+ public i64Array(address: bigint, values: BigInt64Array, force?: boolean): this;
746
+ public i64Array(address: bigint, lengthOrValues: BigInt64Array | number, force?: boolean): BigInt64Array | this {
720
747
  if (typeof lengthOrValues === 'number') {
721
748
  const length = lengthOrValues;
722
749
  const scratch = new BigInt64Array(length);
@@ -728,7 +755,7 @@ class Memory {
728
755
 
729
756
  const values = lengthOrValues;
730
757
 
731
- this.write(address, values);
758
+ void this.write(address, values, force);
732
759
 
733
760
  return this;
734
761
  }
@@ -737,6 +764,7 @@ class Memory {
737
764
  * Reads or writes an 8-bit integer.
738
765
  * @param address Address to access.
739
766
  * @param value Optional value to write.
767
+ * @param force When writing, if true temporarily changes page protection to allow the write.
740
768
  * @returns The int at address, or this instance if writing.
741
769
  * @example
742
770
  * ```ts
@@ -746,8 +774,8 @@ class Memory {
746
774
  * ```
747
775
  */
748
776
  public i8(address: bigint): number;
749
- public i8(address: bigint, value: number): this;
750
- public i8(address: bigint, value?: number): number | this {
777
+ public i8(address: bigint, value: number, force?: boolean): this;
778
+ public i8(address: bigint, value?: number, force?: boolean): number | this {
751
779
  const Scratch1Int8Array = this.Scratch1Int8Array;
752
780
 
753
781
  if (value === undefined) {
@@ -756,7 +784,7 @@ class Memory {
756
784
 
757
785
  Scratch1Int8Array[0x00] = value;
758
786
 
759
- this.write(address, Scratch1Int8Array);
787
+ void this.write(address, Scratch1Int8Array, force);
760
788
 
761
789
  return this;
762
790
  }
@@ -765,6 +793,7 @@ class Memory {
765
793
  * Reads or writes an Int8Array.
766
794
  * @param address Address to access.
767
795
  * @param lengthOrValues Length to read or Int8Array to write.
796
+ * @param force When writing, if true temporarily changes page protection to allow the write.
768
797
  * @returns Int8Array read or this instance if writing.
769
798
  * @example
770
799
  * ```ts
@@ -774,8 +803,8 @@ class Memory {
774
803
  * ```
775
804
  */
776
805
  public i8Array(address: bigint, length: number): Int8Array;
777
- public i8Array(address: bigint, values: Int8Array): this;
778
- public i8Array(address: bigint, lengthOrValues: Int8Array | number): Int8Array | this {
806
+ public i8Array(address: bigint, values: Int8Array, force?: boolean): this;
807
+ public i8Array(address: bigint, lengthOrValues: Int8Array | number, force?: boolean): Int8Array | this {
779
808
  if (typeof lengthOrValues === 'number') {
780
809
  const length = lengthOrValues;
781
810
  const scratch = new Int8Array(length);
@@ -787,7 +816,7 @@ class Memory {
787
816
 
788
817
  const values = lengthOrValues;
789
818
 
790
- this.write(address, values);
819
+ void this.write(address, values, force);
791
820
 
792
821
  return this;
793
822
  }
@@ -796,6 +825,7 @@ class Memory {
796
825
  * Reads or writes a 3x3 matrix (Float32Array of length 9).
797
826
  * @param address Address to access.
798
827
  * @param values Optional Float32Array to write.
828
+ * @param force When writing, if true temporarily changes page protection to allow the write.
799
829
  * @returns The matrix at address, or this instance if writing.
800
830
  * @example
801
831
  * ```ts
@@ -805,8 +835,8 @@ class Memory {
805
835
  * ```
806
836
  */
807
837
  public matrix3x3(address: bigint): Float32Array;
808
- public matrix3x3(address: bigint, values: Float32Array): this;
809
- public matrix3x3(address: bigint, values?: Float32Array): Float32Array | this {
838
+ public matrix3x3(address: bigint, values: Float32Array, force?: boolean): this;
839
+ public matrix3x3(address: bigint, values?: Float32Array, force?: boolean): Float32Array | this {
810
840
  if (values === undefined) {
811
841
  const scratch = new Float32Array(0x09);
812
842
 
@@ -819,7 +849,7 @@ class Memory {
819
849
  throw new RangeError('values.length must be 9.');
820
850
  }
821
851
 
822
- this.write(address, values);
852
+ void this.write(address, values, force);
823
853
 
824
854
  return this;
825
855
  }
@@ -828,6 +858,7 @@ class Memory {
828
858
  * Reads or writes a 3x4 matrix (Float32Array of length 12).
829
859
  * @param address Address to access.
830
860
  * @param values Optional Float32Array to write.
861
+ * @param force When writing, if true temporarily changes page protection to allow the write.
831
862
  * @returns The matrix at address, or this instance if writing.
832
863
  * @example
833
864
  * ```ts
@@ -837,8 +868,8 @@ class Memory {
837
868
  * ```
838
869
  */
839
870
  public matrix3x4(address: bigint): Float32Array;
840
- public matrix3x4(address: bigint, values: Float32Array): this;
841
- public matrix3x4(address: bigint, values?: Float32Array): Float32Array | this {
871
+ public matrix3x4(address: bigint, values: Float32Array, force?: boolean): this;
872
+ public matrix3x4(address: bigint, values?: Float32Array, force?: boolean): Float32Array | this {
842
873
  if (values === undefined) {
843
874
  const scratch = new Float32Array(0x0c);
844
875
 
@@ -851,7 +882,7 @@ class Memory {
851
882
  throw new RangeError('values.length must be 12.');
852
883
  }
853
884
 
854
- this.write(address, values);
885
+ void this.write(address, values, force);
855
886
 
856
887
  return this;
857
888
  }
@@ -860,6 +891,7 @@ class Memory {
860
891
  * Reads or writes a 4x4 matrix (Float32Array of length 16).
861
892
  * @param address Address to access.
862
893
  * @param values Optional Float32Array to write.
894
+ * @param force When writing, if true temporarily changes page protection to allow the write.
863
895
  * @returns The matrix at address, or this instance if writing.
864
896
  * @example
865
897
  * ```ts
@@ -869,8 +901,8 @@ class Memory {
869
901
  * ```
870
902
  */
871
903
  public matrix4x4(address: bigint): Float32Array;
872
- public matrix4x4(address: bigint, values: Float32Array): this;
873
- public matrix4x4(address: bigint, values?: Float32Array): Float32Array | this {
904
+ public matrix4x4(address: bigint, values: Float32Array, force?: boolean): this;
905
+ public matrix4x4(address: bigint, values?: Float32Array, force?: boolean): Float32Array | this {
874
906
  if (values === undefined) {
875
907
  const scratch = new Float32Array(0x10);
876
908
 
@@ -883,7 +915,7 @@ class Memory {
883
915
  throw new RangeError('values.length must be 16.');
884
916
  }
885
917
 
886
- this.write(address, values);
918
+ void this.write(address, values, force);
887
919
 
888
920
  return this;
889
921
  }
@@ -892,6 +924,7 @@ class Memory {
892
924
  * Reads or writes a NetworkUtlVector (Uint32Array).
893
925
  * @param address Address to access.
894
926
  * @param values Optional Uint32Array to write.
927
+ * @param force When writing, if true temporarily changes page protection to allow the write.
895
928
  * @returns The vector at address, or this instance if writing.
896
929
  * @example
897
930
  * ```ts
@@ -901,8 +934,8 @@ class Memory {
901
934
  * ```
902
935
  */
903
936
  public networkUtlVector(address: bigint): NetworkUtlVector;
904
- public networkUtlVector(address: bigint, values: NetworkUtlVector): this;
905
- public networkUtlVector(address: bigint, values?: NetworkUtlVector): NetworkUtlVector | this {
937
+ public networkUtlVector(address: bigint, values: NetworkUtlVector, force?: boolean): this;
938
+ public networkUtlVector(address: bigint, values?: NetworkUtlVector, force?: boolean): NetworkUtlVector | this {
906
939
  const elementsPtr = this.u64(address + 0x08n);
907
940
 
908
941
  if (values === undefined) {
@@ -915,9 +948,9 @@ class Memory {
915
948
  return scratch;
916
949
  }
917
950
 
918
- this.u32(address, values.length);
951
+ this.u32(address, values.length, force);
919
952
 
920
- this.write(elementsPtr, values);
953
+ void this.write(elementsPtr, values, force);
921
954
 
922
955
  return this;
923
956
  }
@@ -926,6 +959,7 @@ class Memory {
926
959
  * Reads or writes a Point (object with x, y).
927
960
  * @param address Address to access.
928
961
  * @param value Optional Point to write.
962
+ * @param force When writing, if true temporarily changes page protection to allow the write.
929
963
  * @returns The point at address, or this instance if writing.
930
964
  * @example
931
965
  * ```ts
@@ -935,8 +969,8 @@ class Memory {
935
969
  * ```
936
970
  */
937
971
  public point(address: bigint): Point;
938
- public point(address: bigint, value: Point): this;
939
- public point(address: bigint, value?: Point): Point | this {
972
+ public point(address: bigint, value: Point, force?: boolean): this;
973
+ public point(address: bigint, value?: Point, force?: boolean): Point | this {
940
974
  const Scratch8Float32Array = this.Scratch8Float32Array;
941
975
 
942
976
  if (value === undefined) {
@@ -951,7 +985,7 @@ class Memory {
951
985
  Scratch8Float32Array[0x00] = value.x;
952
986
  Scratch8Float32Array[0x01] = value.y;
953
987
 
954
- this.write(address, Scratch8Float32Array);
988
+ void this.write(address, Scratch8Float32Array, force);
955
989
 
956
990
  return this;
957
991
  }
@@ -960,6 +994,7 @@ class Memory {
960
994
  * Reads or writes an array of Points.
961
995
  * @param address Address to access.
962
996
  * @param lengthOrValues Length to read or array to write.
997
+ * @param force When writing, if true temporarily changes page protection to allow the write.
963
998
  * @returns Array of points read or this instance if writing.
964
999
  * @example
965
1000
  * ```ts
@@ -969,8 +1004,8 @@ class Memory {
969
1004
  * ```
970
1005
  */
971
1006
  public pointArray(address: bigint, length: number): Point[];
972
- public pointArray(address: bigint, value: Point[]): this;
973
- public pointArray(address: bigint, lengthOrValues: number | Point[]): Point[] | this {
1007
+ public pointArray(address: bigint, value: Point[], force?: boolean): this;
1008
+ public pointArray(address: bigint, lengthOrValues: number | Point[], force?: boolean): Point[] | this {
974
1009
  if (typeof lengthOrValues === 'number') {
975
1010
  const length = lengthOrValues;
976
1011
  const scratch = new Float32Array(length * 2);
@@ -999,14 +1034,27 @@ class Memory {
999
1034
  scratch[j + 0x01] = vector2.y;
1000
1035
  }
1001
1036
 
1002
- this.write(address, scratch);
1037
+ void this.write(address, scratch, force);
1003
1038
 
1004
1039
  return this;
1005
1040
  }
1006
1041
 
1042
+ /**
1043
+ * Reads or writes a raw Point (two Float32 values) as a Float32Array.
1044
+ * @param address Address to access.
1045
+ * @param values Optional Float32Array of length 2 to write.
1046
+ * @param force When writing, if true temporarily changes page protection to allow the write.
1047
+ * @returns Float32Array read or this instance if writing.
1048
+ * @example
1049
+ * ```ts
1050
+ * const cs2 = new Memory('cs2.exe');
1051
+ * const myPoint = cs2.pointRaw(0x12345678n);
1052
+ * cs2.pointRaw(0x12345678n, new Float32Array([1, 2]));
1053
+ * ```
1054
+ */
1007
1055
  public pointRaw(address: bigint): Float32Array;
1008
- public pointRaw(address: bigint, values: Float32Array): this;
1009
- public pointRaw(address: bigint, values?: Float32Array): Float32Array | this {
1056
+ public pointRaw(address: bigint, values: Float32Array, force?: boolean): this;
1057
+ public pointRaw(address: bigint, values?: Float32Array, force?: boolean): Float32Array | this {
1010
1058
  if (values === undefined) {
1011
1059
  return this.f32Array(address, 0x02);
1012
1060
  }
@@ -1015,7 +1063,7 @@ class Memory {
1015
1063
  throw new RangeError('values.length must be 2.');
1016
1064
  }
1017
1065
 
1018
- this.write(address, values);
1066
+ void this.write(address, values, force);
1019
1067
 
1020
1068
  return this;
1021
1069
  }
@@ -1033,8 +1081,8 @@ class Memory {
1033
1081
  * ```
1034
1082
  */
1035
1083
  public qAngle(address: bigint): QAngle;
1036
- public qAngle(address: bigint, value: QAngle): this;
1037
- public qAngle(address: bigint, value?: QAngle): QAngle | this {
1084
+ public qAngle(address: bigint, value: QAngle, force?: boolean): this;
1085
+ public qAngle(address: bigint, value?: QAngle, force?: boolean): QAngle | this {
1038
1086
  const Scratch12Float32Array = this.Scratch12Float32Array;
1039
1087
 
1040
1088
  if (value === undefined) {
@@ -1051,7 +1099,7 @@ class Memory {
1051
1099
  Scratch12Float32Array[0x02] = value.roll;
1052
1100
  Scratch12Float32Array[0x01] = value.yaw;
1053
1101
 
1054
- this.write(address, Scratch12Float32Array);
1102
+ void this.write(address, Scratch12Float32Array, force);
1055
1103
 
1056
1104
  return this;
1057
1105
  }
@@ -1069,8 +1117,8 @@ class Memory {
1069
1117
  * ```
1070
1118
  */
1071
1119
  public qAngleArray(address: bigint, length: number): QAngle[];
1072
- public qAngleArray(address: bigint, values: QAngle[]): this;
1073
- public qAngleArray(address: bigint, lengthOrValues: QAngle[] | number): QAngle[] | this {
1120
+ public qAngleArray(address: bigint, values: QAngle[], force?: boolean): this;
1121
+ public qAngleArray(address: bigint, lengthOrValues: QAngle[] | number, force?: boolean): QAngle[] | this {
1074
1122
  if (typeof lengthOrValues === 'number') {
1075
1123
  const length = lengthOrValues;
1076
1124
  const scratch = new Float32Array(length * 0x03);
@@ -1101,7 +1149,7 @@ class Memory {
1101
1149
  scratch[j + 0x01] = qAngle.yaw;
1102
1150
  }
1103
1151
 
1104
- this.write(address, scratch);
1152
+ void this.write(address, scratch, force);
1105
1153
 
1106
1154
  return this;
1107
1155
  }
@@ -1110,6 +1158,7 @@ class Memory {
1110
1158
  * Reads or writes a raw QAngle as a Float32Array.
1111
1159
  * @param address Address to access.
1112
1160
  * @param values Optional Float32Array to write.
1161
+ * @param force When writing, if true temporarily changes page protection to allow the write.
1113
1162
  * @returns Float32Array read or this instance if writing.
1114
1163
  * @example
1115
1164
  * ```ts
@@ -1119,8 +1168,8 @@ class Memory {
1119
1168
  * ```
1120
1169
  */
1121
1170
  public qAngleRaw(address: bigint): Float32Array;
1122
- public qAngleRaw(address: bigint, values: Float32Array): this;
1123
- public qAngleRaw(address: bigint, values?: Float32Array): Float32Array | this {
1171
+ public qAngleRaw(address: bigint, values: Float32Array, force?: boolean): this;
1172
+ public qAngleRaw(address: bigint, values?: Float32Array, force?: boolean): Float32Array | this {
1124
1173
  if (values === undefined) {
1125
1174
  return this.f32Array(address, 0x03);
1126
1175
  }
@@ -1129,7 +1178,7 @@ class Memory {
1129
1178
  throw new RangeError('values.length must be 3.');
1130
1179
  }
1131
1180
 
1132
- this.write(address, values);
1181
+ void this.write(address, values, force);
1133
1182
 
1134
1183
  return this;
1135
1184
  }
@@ -1138,6 +1187,7 @@ class Memory {
1138
1187
  * Reads or writes a Quaternion (object with w, x, y, z).
1139
1188
  * @param address Address to access.
1140
1189
  * @param value Optional Quaternion to write.
1190
+ * @param force When writing, if true temporarily changes page protection to allow the write.
1141
1191
  * @returns The Quaternion at address, or this instance if writing.
1142
1192
  * @example
1143
1193
  * ```ts
@@ -1147,8 +1197,8 @@ class Memory {
1147
1197
  * ```
1148
1198
  */
1149
1199
  public quaternion(address: bigint): Quaternion;
1150
- public quaternion(address: bigint, value: Quaternion): this;
1151
- public quaternion(address: bigint, value?: Quaternion): Quaternion | this {
1200
+ public quaternion(address: bigint, value: Quaternion, force?: boolean): this;
1201
+ public quaternion(address: bigint, value?: Quaternion, force?: boolean): Quaternion | this {
1152
1202
  const Scratch16Float32Array = this.Scratch16Float32Array;
1153
1203
 
1154
1204
  if (value === undefined) {
@@ -1167,7 +1217,7 @@ class Memory {
1167
1217
  Scratch16Float32Array[0x01] = value.y;
1168
1218
  Scratch16Float32Array[0x02] = value.z;
1169
1219
 
1170
- this.write(address, Scratch16Float32Array);
1220
+ void this.write(address, Scratch16Float32Array, force);
1171
1221
 
1172
1222
  return this;
1173
1223
  }
@@ -1176,6 +1226,7 @@ class Memory {
1176
1226
  * Reads or writes an array of Quaternions.
1177
1227
  * @param address Address to access.
1178
1228
  * @param lengthOrValues Length to read or array to write.
1229
+ * @param force When writing, if true temporarily changes page protection to allow the write.
1179
1230
  * @returns Array of Quaternions read or this instance if writing.
1180
1231
  * @example
1181
1232
  * ```ts
@@ -1185,8 +1236,8 @@ class Memory {
1185
1236
  * ```
1186
1237
  */
1187
1238
  public quaternionArray(address: bigint, length: number): Quaternion[];
1188
- public quaternionArray(address: bigint, values: Quaternion[]): this;
1189
- public quaternionArray(address: bigint, lengthOrValues: Quaternion[] | number): Quaternion[] | this {
1239
+ public quaternionArray(address: bigint, values: Quaternion[], force?: boolean): this;
1240
+ public quaternionArray(address: bigint, lengthOrValues: Quaternion[] | number, force?: boolean): Quaternion[] | this {
1190
1241
  if (typeof lengthOrValues === 'number') {
1191
1242
  const length = lengthOrValues;
1192
1243
  const scratch = new Float32Array(length * 0x04); // 4 * f32 per Quaternion
@@ -1219,7 +1270,7 @@ class Memory {
1219
1270
  scratch[j + 0x02] = quaternion.z;
1220
1271
  }
1221
1272
 
1222
- this.write(address, scratch);
1273
+ void this.write(address, scratch, force);
1223
1274
 
1224
1275
  return this;
1225
1276
  }
@@ -1228,6 +1279,7 @@ class Memory {
1228
1279
  * Reads or writes a raw Quaternion as a Float32Array.
1229
1280
  * @param address Address to access.
1230
1281
  * @param values Optional Float32Array to write.
1282
+ * @param force When writing, if true temporarily changes page protection to allow the write.
1231
1283
  * @returns Float32Array read or this instance if writing.
1232
1284
  * @example
1233
1285
  * ```ts
@@ -1237,8 +1289,8 @@ class Memory {
1237
1289
  * ```
1238
1290
  */
1239
1291
  public quaternionRaw(address: bigint): Float32Array;
1240
- public quaternionRaw(address: bigint, values: Float32Array): this;
1241
- public quaternionRaw(address: bigint, values?: Float32Array): Float32Array | this {
1292
+ public quaternionRaw(address: bigint, values: Float32Array, force?: boolean): this;
1293
+ public quaternionRaw(address: bigint, values?: Float32Array, force?: boolean): Float32Array | this {
1242
1294
  if (values === undefined) {
1243
1295
  return this.f32Array(address, 0x04);
1244
1296
  }
@@ -1247,7 +1299,7 @@ class Memory {
1247
1299
  throw new RangeError('values.length must be 4.');
1248
1300
  }
1249
1301
 
1250
- this.write(address, values);
1302
+ void this.write(address, values, force);
1251
1303
 
1252
1304
  return this;
1253
1305
  }
@@ -1256,6 +1308,7 @@ class Memory {
1256
1308
  * Reads or writes an RGB color (object with r, g, b).
1257
1309
  * @param address Address to access.
1258
1310
  * @param value Optional RGB to write.
1311
+ * @param force When writing, if true temporarily changes page protection to allow the write.
1259
1312
  * @returns The RGB at address, or this instance if writing.
1260
1313
  * @example
1261
1314
  * ```ts
@@ -1265,8 +1318,8 @@ class Memory {
1265
1318
  * ```
1266
1319
  */
1267
1320
  public rgb(address: bigint): RGB;
1268
- public rgb(address: bigint, value: RGB): this;
1269
- public rgb(address: bigint, value?: RGB): RGB | this {
1321
+ public rgb(address: bigint, value: RGB, force?: boolean): this;
1322
+ public rgb(address: bigint, value?: RGB, force?: boolean): RGB | this {
1270
1323
  const Scratch3 = this.Scratch3;
1271
1324
 
1272
1325
  if (value === undefined) {
@@ -1283,13 +1336,16 @@ class Memory {
1283
1336
  Scratch3[0x01] = value.g;
1284
1337
  Scratch3[0x02] = value.b;
1285
1338
 
1286
- return this.write(address, Scratch3);
1339
+ void this.write(address, Scratch3, force);
1340
+
1341
+ return this;
1287
1342
  }
1288
1343
 
1289
1344
  /**
1290
1345
  * Reads or writes a raw RGB value as a Uint8Array.
1291
1346
  * @param address Address to access.
1292
1347
  * @param values Optional buffer to write.
1348
+ * @param force When writing, if true temporarily changes page protection to allow the write.
1293
1349
  * @returns Uint8Array read or this instance if writing.
1294
1350
  * @example
1295
1351
  * ```ts
@@ -1299,8 +1355,9 @@ class Memory {
1299
1355
  * ```
1300
1356
  */
1301
1357
  public rgbRaw(address: bigint): Uint8Array;
1302
- public rgbRaw(address: bigint, values: Buffer | Uint8Array | Uint8ClampedArray): this;
1303
- public rgbRaw(address: bigint, values?: Buffer | Uint8Array | Uint8ClampedArray): Uint8Array | this {
1358
+ public rgbRaw(address: bigint): Uint8Array;
1359
+ public rgbRaw(address: bigint, values: Buffer | Uint8Array | Uint8ClampedArray, force?: boolean): this;
1360
+ public rgbRaw(address: bigint, values?: Buffer | Uint8Array | Uint8ClampedArray, force?: boolean): Uint8Array | this {
1304
1361
  if (values === undefined) {
1305
1362
  return this.u8Array(address, 0x03);
1306
1363
  }
@@ -1309,7 +1366,7 @@ class Memory {
1309
1366
  throw new RangeError('values.length must be 3.');
1310
1367
  }
1311
1368
 
1312
- this.write(address, values);
1369
+ void this.write(address, values, force);
1313
1370
 
1314
1371
  return this;
1315
1372
  }
@@ -1318,6 +1375,7 @@ class Memory {
1318
1375
  * Reads or writes an RGBA color (object with r, g, b, a).
1319
1376
  * @param address Address to access.
1320
1377
  * @param value Optional RGBA to write.
1378
+ * @param force When writing, if true temporarily changes page protection to allow the write.
1321
1379
  * @returns The RGBA at address, or this instance if writing.
1322
1380
  * @example
1323
1381
  * ```ts
@@ -1327,8 +1385,8 @@ class Memory {
1327
1385
  * ```
1328
1386
  */
1329
1387
  public rgba(address: bigint): RGBA;
1330
- public rgba(address: bigint, value: RGBA): this;
1331
- public rgba(address: bigint, value?: RGBA): RGBA | this {
1388
+ public rgba(address: bigint, value: RGBA, force?: boolean): this;
1389
+ public rgba(address: bigint, value?: RGBA, force?: boolean): RGBA | this {
1332
1390
  const Scratch4 = this.Scratch4;
1333
1391
 
1334
1392
  if (value === undefined) {
@@ -1347,13 +1405,16 @@ class Memory {
1347
1405
  Scratch4[0x02] = value.b;
1348
1406
  Scratch4[0x03] = value.a;
1349
1407
 
1350
- return this.write(address, Scratch4);
1408
+ void this.write(address, Scratch4, force);
1409
+
1410
+ return this;
1351
1411
  }
1352
1412
 
1353
1413
  /**
1354
1414
  * Reads or writes a raw RGBA value as a Uint8Array.
1355
1415
  * @param address Address to access.
1356
1416
  * @param values Optional buffer to write.
1417
+ * @param force When writing, if true temporarily changes page protection to allow the write.
1357
1418
  * @returns Uint8Array read or this instance if writing.
1358
1419
  * @example
1359
1420
  * ```ts
@@ -1363,8 +1424,9 @@ class Memory {
1363
1424
  * ```
1364
1425
  */
1365
1426
  public rgbaRaw(address: bigint): Uint8Array;
1366
- public rgbaRaw(address: bigint, values: Buffer | Uint8Array | Uint8ClampedArray): this;
1367
- public rgbaRaw(address: bigint, values?: Buffer | Uint8Array | Uint8ClampedArray): Uint8Array | this {
1427
+ public rgbaRaw(address: bigint): Uint8Array;
1428
+ public rgbaRaw(address: bigint, values: Buffer | Uint8Array | Uint8ClampedArray, force?: boolean): this;
1429
+ public rgbaRaw(address: bigint, values?: Buffer | Uint8Array | Uint8ClampedArray, force?: boolean): Uint8Array | this {
1368
1430
  if (values === undefined) {
1369
1431
  return this.u8Array(address, 0x04);
1370
1432
  }
@@ -1373,7 +1435,7 @@ class Memory {
1373
1435
  throw new RangeError('values.length must be 4.');
1374
1436
  }
1375
1437
 
1376
- this.write(address, values);
1438
+ void this.write(address, values, force);
1377
1439
 
1378
1440
  return this;
1379
1441
  }
@@ -1382,8 +1444,10 @@ class Memory {
1382
1444
  * Reads or writes a UTF-8 string.
1383
1445
  * @param address Address to access.
1384
1446
  * @param lengthOrValue Length to read or string to write.
1447
+ * @param force When writing, if true temporarily changes page protection to allow the write.
1385
1448
  * @returns The string at address, or this instance if writing.
1386
1449
  * @notice When writing, remember to null-terminate your string (e.g., 'hello\0').
1450
+ * @todo Compare performance when using CString vs TextDecoder when reading…
1387
1451
  * @example
1388
1452
  * ```ts
1389
1453
  * const cs2 = new Memory('cs2.exe');
@@ -1392,8 +1456,9 @@ class Memory {
1392
1456
  * ```
1393
1457
  */
1394
1458
  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 {
1459
+ public string(address: bigint, length: number): string;
1460
+ public string(address: bigint, value: string, force?: boolean): this;
1461
+ public string(address: bigint, lengthOrValue: number | string, force?: boolean): string | this {
1397
1462
  if (typeof lengthOrValue === 'number') {
1398
1463
  const scratch = new Uint8Array(lengthOrValue);
1399
1464
 
@@ -1410,7 +1475,7 @@ class Memory {
1410
1475
 
1411
1476
  const scratch = Memory.TextEncoderUTF8.encode(lengthOrValue);
1412
1477
 
1413
- this.write(address, scratch);
1478
+ void this.write(address, scratch, force);
1414
1479
 
1415
1480
  return this;
1416
1481
  }
@@ -1419,6 +1484,7 @@ class Memory {
1419
1484
  * Reads or writes a 16-bit unsigned integer.
1420
1485
  * @param address Address to access.
1421
1486
  * @param value Optional value to write.
1487
+ * @param force When writing, if true temporarily changes page protection to allow the write.
1422
1488
  * @returns The value at address, or this instance if writing.
1423
1489
  * @example
1424
1490
  * ```ts
@@ -1428,8 +1494,8 @@ class Memory {
1428
1494
  * ```
1429
1495
  */
1430
1496
  public u16(address: bigint): number;
1431
- public u16(address: bigint, value: number): this;
1432
- public u16(address: bigint, value?: number): number | this {
1497
+ public u16(address: bigint, value: number, force?: boolean): this;
1498
+ public u16(address: bigint, value?: number, force?: boolean): number | this {
1433
1499
  const Scratch2Uint16Array = this.Scratch2Uint16Array;
1434
1500
 
1435
1501
  if (value === undefined) {
@@ -1438,7 +1504,7 @@ class Memory {
1438
1504
 
1439
1505
  Scratch2Uint16Array[0x00] = value;
1440
1506
 
1441
- this.write(address, Scratch2Uint16Array);
1507
+ void this.write(address, Scratch2Uint16Array, force);
1442
1508
 
1443
1509
  return this;
1444
1510
  }
@@ -1447,6 +1513,7 @@ class Memory {
1447
1513
  * Reads or writes a Uint16Array.
1448
1514
  * @param address Address to access.
1449
1515
  * @param lengthOrValues Length to read or Uint16Array to write.
1516
+ * @param force When writing, if true temporarily changes page protection to allow the write.
1450
1517
  * @returns Uint16Array read or this instance if writing.
1451
1518
  * @example
1452
1519
  * ```ts
@@ -1456,8 +1523,8 @@ class Memory {
1456
1523
  * ```
1457
1524
  */
1458
1525
  public u16Array(address: bigint, length: number): Uint16Array;
1459
- public u16Array(address: bigint, values: Uint16Array): this;
1460
- public u16Array(address: bigint, lengthOrValues: Uint16Array | number): Uint16Array | this {
1526
+ public u16Array(address: bigint, values: Uint16Array, force?: boolean): this;
1527
+ public u16Array(address: bigint, lengthOrValues: Uint16Array | number, force?: boolean): Uint16Array | this {
1461
1528
  if (typeof lengthOrValues === 'number') {
1462
1529
  const length = lengthOrValues;
1463
1530
  const scratch = new Uint16Array(length);
@@ -1469,7 +1536,7 @@ class Memory {
1469
1536
 
1470
1537
  const values = lengthOrValues;
1471
1538
 
1472
- this.write(address, values);
1539
+ void this.write(address, values, force);
1473
1540
 
1474
1541
  return this;
1475
1542
  }
@@ -1478,6 +1545,7 @@ class Memory {
1478
1545
  * Reads or writes a 32-bit unsigned integer.
1479
1546
  * @param address Address to access.
1480
1547
  * @param value Optional value to write.
1548
+ * @param force When writing, if true temporarily changes page protection to allow the write.
1481
1549
  * @returns The value at address, or this instance if writing.
1482
1550
  * @example
1483
1551
  * ```ts
@@ -1487,8 +1555,8 @@ class Memory {
1487
1555
  * ```
1488
1556
  */
1489
1557
  public u32(address: bigint): number;
1490
- public u32(address: bigint, value: number): this;
1491
- public u32(address: bigint, value?: number): number | this {
1558
+ public u32(address: bigint, value: number, force?: boolean): this;
1559
+ public u32(address: bigint, value?: number, force?: boolean): number | this {
1492
1560
  const Scratch4Uint32Array = this.Scratch4Uint32Array;
1493
1561
 
1494
1562
  if (value === undefined) {
@@ -1497,7 +1565,7 @@ class Memory {
1497
1565
 
1498
1566
  Scratch4Uint32Array[0x00] = value;
1499
1567
 
1500
- this.write(address, Scratch4Uint32Array);
1568
+ void this.write(address, Scratch4Uint32Array, force);
1501
1569
 
1502
1570
  return this;
1503
1571
  }
@@ -1506,6 +1574,7 @@ class Memory {
1506
1574
  * Reads or writes a Uint32Array.
1507
1575
  * @param address Address to access.
1508
1576
  * @param lengthOrValues Length to read or Uint32Array to write.
1577
+ * @param force When writing, if true temporarily changes page protection to allow the write.
1509
1578
  * @returns Uint32Array read or this instance if writing.
1510
1579
  * @example
1511
1580
  * ```ts
@@ -1515,8 +1584,8 @@ class Memory {
1515
1584
  * ```
1516
1585
  */
1517
1586
  public u32Array(address: bigint, length: number): Uint32Array;
1518
- public u32Array(address: bigint, values: Uint32Array): this;
1519
- public u32Array(address: bigint, lengthOrValues: Uint32Array | number): Uint32Array | this {
1587
+ public u32Array(address: bigint, values: Uint32Array, force?: boolean): this;
1588
+ public u32Array(address: bigint, lengthOrValues: Uint32Array | number, force?: boolean): Uint32Array | this {
1520
1589
  if (typeof lengthOrValues === 'number') {
1521
1590
  const length = lengthOrValues;
1522
1591
  const scratch = new Uint32Array(length);
@@ -1528,7 +1597,7 @@ class Memory {
1528
1597
 
1529
1598
  const values = lengthOrValues;
1530
1599
 
1531
- this.write(address, values);
1600
+ void this.write(address, values, force);
1532
1601
 
1533
1602
  return this;
1534
1603
  }
@@ -1537,6 +1606,7 @@ class Memory {
1537
1606
  * Reads or writes a 64-bit unsigned integer.
1538
1607
  * @param address Address to access.
1539
1608
  * @param value Optional value to write.
1609
+ * @param force When writing, if true temporarily changes page protection to allow the write.
1540
1610
  * @returns The bigint at address, or this instance if writing.
1541
1611
  * @example
1542
1612
  * ```ts
@@ -1546,8 +1616,8 @@ class Memory {
1546
1616
  * ```
1547
1617
  */
1548
1618
  public u64(address: bigint): bigint;
1549
- public u64(address: bigint, value: bigint): this;
1550
- public u64(address: bigint, value?: bigint): bigint | this {
1619
+ public u64(address: bigint, value: bigint, force?: boolean): this;
1620
+ public u64(address: bigint, value?: bigint, force?: boolean): bigint | this {
1551
1621
  const Scratch8BigUint64Array = this.Scratch8BigUint64Array;
1552
1622
 
1553
1623
  if (value === undefined) {
@@ -1556,7 +1626,7 @@ class Memory {
1556
1626
 
1557
1627
  Scratch8BigUint64Array[0x00] = value;
1558
1628
 
1559
- this.write(address, Scratch8BigUint64Array);
1629
+ void this.write(address, Scratch8BigUint64Array, force);
1560
1630
 
1561
1631
  return this;
1562
1632
  }
@@ -1565,6 +1635,7 @@ class Memory {
1565
1635
  * Reads or writes a BigUint64Array.
1566
1636
  * @param address Address to access.
1567
1637
  * @param lengthOrValues Length to read or BigUint64Array to write.
1638
+ * @param force When writing, if true temporarily changes page protection to allow the write.
1568
1639
  * @returns BigUint64Array read or this instance if writing.
1569
1640
  * @example
1570
1641
  * ```ts
@@ -1574,8 +1645,8 @@ class Memory {
1574
1645
  * ```
1575
1646
  */
1576
1647
  public u64Array(address: bigint, length: number): BigUint64Array;
1577
- public u64Array(address: bigint, values: BigUint64Array): this;
1578
- public u64Array(address: bigint, lengthOrValues: BigUint64Array | number): BigUint64Array | this {
1648
+ public u64Array(address: bigint, values: BigUint64Array, force?: boolean): this;
1649
+ public u64Array(address: bigint, lengthOrValues: BigUint64Array | number, force?: boolean): BigUint64Array | this {
1579
1650
  if (typeof lengthOrValues === 'number') {
1580
1651
  const length = lengthOrValues;
1581
1652
  const scratch = new BigUint64Array(length);
@@ -1587,7 +1658,7 @@ class Memory {
1587
1658
 
1588
1659
  const values = lengthOrValues;
1589
1660
 
1590
- this.write(address, values);
1661
+ void this.write(address, values, force);
1591
1662
 
1592
1663
  return this;
1593
1664
  }
@@ -1596,6 +1667,7 @@ class Memory {
1596
1667
  * Reads or writes an 8-bit unsigned integer.
1597
1668
  * @param address Address to access.
1598
1669
  * @param value Optional value to write.
1670
+ * @param force When writing, if true temporarily changes page protection to allow the write.
1599
1671
  * @returns The value at address, or this instance if writing.
1600
1672
  * @example
1601
1673
  * ```ts
@@ -1605,8 +1677,8 @@ class Memory {
1605
1677
  * ```
1606
1678
  */
1607
1679
  public u8(address: bigint): number;
1608
- public u8(address: bigint, value: number): this;
1609
- public u8(address: bigint, value?: number): number | this {
1680
+ public u8(address: bigint, value: number, force?: boolean): this;
1681
+ public u8(address: bigint, value?: number, force?: boolean): number | this {
1610
1682
  const Scratch1 = this.Scratch1;
1611
1683
 
1612
1684
  if (value === undefined) {
@@ -1615,7 +1687,7 @@ class Memory {
1615
1687
 
1616
1688
  Scratch1[0x00] = value;
1617
1689
 
1618
- this.write(address, Scratch1);
1690
+ void this.write(address, Scratch1, force);
1619
1691
 
1620
1692
  return this;
1621
1693
  }
@@ -1624,6 +1696,7 @@ class Memory {
1624
1696
  * Reads or writes a Uint8Array.
1625
1697
  * @param address Address to access.
1626
1698
  * @param lengthOrValues Length to read or Uint8Array to write.
1699
+ * @param force When writing, if true temporarily changes page protection to allow the write.
1627
1700
  * @returns Uint8Array read or this instance if writing.
1628
1701
  * @example
1629
1702
  * ```ts
@@ -1633,8 +1706,8 @@ class Memory {
1633
1706
  * ```
1634
1707
  */
1635
1708
  public u8Array(address: bigint, length: number): Uint8Array;
1636
- public u8Array(address: bigint, values: Uint8Array): this;
1637
- public u8Array(address: bigint, lengthOrValues: Uint8Array | number): Uint8Array | this {
1709
+ public u8Array(address: bigint, values: Uint8Array, force?: boolean): this;
1710
+ public u8Array(address: bigint, lengthOrValues: Uint8Array | number, force?: boolean): Uint8Array | this {
1638
1711
  if (typeof lengthOrValues === 'number') {
1639
1712
  const length = lengthOrValues;
1640
1713
  const scratch = new Uint8Array(length);
@@ -1646,7 +1719,7 @@ class Memory {
1646
1719
 
1647
1720
  const values = lengthOrValues;
1648
1721
 
1649
- this.write(address, values);
1722
+ void this.write(address, values, force);
1650
1723
 
1651
1724
  return this;
1652
1725
  }
@@ -1655,6 +1728,7 @@ class Memory {
1655
1728
  * Reads or writes a pointer-sized unsigned integer.
1656
1729
  * @param address Address to access.
1657
1730
  * @param value Optional value to write.
1731
+ * @param force When writing, if true temporarily changes page protection to allow the write.
1658
1732
  * @returns The value at address, or this instance if writing.
1659
1733
  * @example
1660
1734
  * ```ts
@@ -1664,20 +1738,21 @@ class Memory {
1664
1738
  * ```
1665
1739
  */
1666
1740
  public uPtr(address: bigint): UPtr;
1667
- public uPtr(address: bigint, value: UPtr): this;
1668
- public uPtr(address: bigint, value?: UPtr): UPtr | this {
1741
+ public uPtr(address: bigint, value: UPtr, force?: boolean): this;
1742
+ public uPtr(address: bigint, value?: UPtr, force?: boolean): UPtr | this {
1669
1743
  // TypeScript is funny sometimes, isn't it?… 🫠…
1670
1744
  if (value === undefined) {
1671
1745
  return this.u64(address);
1672
1746
  }
1673
1747
 
1674
- return this.u64(address, value);
1748
+ return this.u64(address, value, force);
1675
1749
  }
1676
1750
 
1677
1751
  /**
1678
1752
  * Reads or writes an array of pointer-sized unsigned integers.
1679
1753
  * @param address Address to access.
1680
1754
  * @param lengthOrValues Length to read or array to write.
1755
+ * @param force When writing, if true temporarily changes page protection to allow the write.
1681
1756
  * @returns Array read or this instance if writing.
1682
1757
  * @example
1683
1758
  * ```ts
@@ -1687,20 +1762,21 @@ class Memory {
1687
1762
  * ```
1688
1763
  */
1689
1764
  public uPtrArray(address: bigint, length: number): UPtrArray;
1690
- public uPtrArray(address: bigint, values: UPtrArray): this;
1691
- public uPtrArray(address: bigint, lengthOrValues: UPtrArray | number): UPtrArray | this {
1765
+ public uPtrArray(address: bigint, values: UPtrArray, force?: boolean): this;
1766
+ public uPtrArray(address: bigint, lengthOrValues: UPtrArray | number, force?: boolean): UPtrArray | this {
1692
1767
  // TypeScript is funny sometimes, isn't it?… 🫠…
1693
1768
  if (typeof lengthOrValues === 'number') {
1694
1769
  return this.u64Array(address, lengthOrValues);
1695
1770
  }
1696
1771
 
1697
- return this.u64Array(address, lengthOrValues);
1772
+ return this.u64Array(address, lengthOrValues, force);
1698
1773
  }
1699
1774
 
1700
1775
  /**
1701
1776
  * Reads or writes a Vector2 (object with x, y).
1702
1777
  * @param address Address to access.
1703
1778
  * @param value Optional Vector2 to write.
1779
+ * @param force When writing, if true temporarily changes page protection to allow the write.
1704
1780
  * @returns The Vector2 at address, or this instance if writing.
1705
1781
  * @example
1706
1782
  * ```ts
@@ -1710,42 +1786,56 @@ class Memory {
1710
1786
  * ```
1711
1787
  */
1712
1788
  public vector2(address: bigint): Vector2;
1713
- public vector2(address: bigint, value: Vector2): this;
1714
- public vector2(address: bigint, value?: Vector2): Vector2 | this {
1789
+ public vector2(address: bigint, value: Vector2, force?: boolean): this;
1790
+ public vector2(address: bigint, value?: Vector2, force?: boolean): Vector2 | this {
1715
1791
  // TypeScript is funny sometimes, isn't it?… 🫠…
1716
1792
  if (value === undefined) {
1717
1793
  return this.point(address);
1718
1794
  }
1719
1795
 
1720
- return this.point(address, value);
1796
+ return this.point(address, value, force);
1721
1797
  }
1722
1798
 
1723
1799
  /**
1724
1800
  * Reads or writes an array of Vector2.
1725
1801
  * @param address Address to access.
1726
1802
  * @param lengthOrValues Length to read or array to write.
1803
+ * @param force When writing, if true temporarily changes page protection to allow the write.
1727
1804
  * @returns Array of Vector2 read or this instance if writing.
1728
1805
  * @example
1729
1806
  * ```ts
1730
1807
  * const cs2 = new Memory('cs2.exe');
1731
- * const myVectors = cs2.vector2Array(0x12345678n, 2);
1808
+ * const myVector2s = cs2.vector2Array(0x12345678n, 2);
1732
1809
  * cs2.vector2Array(0x12345678n, [{ x: 1, y: 2 }, { x: 3, y: 4 }]);
1733
1810
  * ```
1734
1811
  */
1735
1812
  public vector2Array(address: bigint, length: number): Vector2[];
1736
- public vector2Array(address: bigint, values: Vector2[]): this;
1737
- public vector2Array(address: bigint, lengthOrValues: Vector2[] | number): Vector2[] | this {
1813
+ public vector2Array(address: bigint, values: Vector2[], force?: boolean): this;
1814
+ public vector2Array(address: bigint, lengthOrValues: Vector2[] | number, force?: boolean): Vector2[] | this {
1738
1815
  // TypeScript is funny sometimes, isn't it?… 🫠…
1739
1816
  if (typeof lengthOrValues === 'number') {
1740
1817
  return this.pointArray(address, lengthOrValues);
1741
1818
  }
1742
1819
 
1743
- return this.pointArray(address, lengthOrValues);
1820
+ return this.pointArray(address, lengthOrValues, force);
1744
1821
  }
1745
1822
 
1823
+ /**
1824
+ * Reads or writes a raw Vector2 as a Float32Array.
1825
+ * @param address Address to access.
1826
+ * @param values Optional Float32Array to write.
1827
+ * @param force When writing, if true temporarily changes page protection to allow the write.
1828
+ * @returns Float32Array read or this instance if writing.
1829
+ * @example
1830
+ * ```ts
1831
+ * const cs2 = new Memory('cs2.exe');
1832
+ * const myVector2 = cs2.vector2Raw(0x12345678n);
1833
+ * cs2.vector2Raw(0x12345678n, new Float32Array([1, 2]));
1834
+ * ```
1835
+ */
1746
1836
  public vector2Raw(address: bigint): Float32Array;
1747
- public vector2Raw(address: bigint, values: Float32Array): this;
1748
- public vector2Raw(address: bigint, values?: Float32Array): Float32Array | this {
1837
+ public vector2Raw(address: bigint, values: Float32Array, force?: boolean): this;
1838
+ public vector2Raw(address: bigint, values?: Float32Array, force?: boolean): Float32Array | this {
1749
1839
  if (values === undefined) {
1750
1840
  return this.f32Array(address, 0x02);
1751
1841
  }
@@ -1754,7 +1844,7 @@ class Memory {
1754
1844
  throw new RangeError('values.length must be 2.');
1755
1845
  }
1756
1846
 
1757
- this.write(address, values);
1847
+ void this.write(address, values, force);
1758
1848
 
1759
1849
  return this;
1760
1850
  }
@@ -1763,6 +1853,7 @@ class Memory {
1763
1853
  * Reads or writes a Vector3 (object with x, y, z).
1764
1854
  * @param address Address to access.
1765
1855
  * @param value Optional Vector3 to write.
1856
+ * @param force When writing, if true temporarily changes page protection to allow the write.
1766
1857
  * @returns The Vector3 at address, or this instance if writing.
1767
1858
  * @example
1768
1859
  * ```ts
@@ -1772,8 +1863,8 @@ class Memory {
1772
1863
  * ```
1773
1864
  */
1774
1865
  public vector3(address: bigint): Vector3;
1775
- public vector3(address: bigint, value: Vector3): this;
1776
- public vector3(address: bigint, value?: Vector3): Vector3 | this {
1866
+ public vector3(address: bigint, value: Vector3, force?: boolean): this;
1867
+ public vector3(address: bigint, value?: Vector3, force?: boolean): Vector3 | this {
1777
1868
  const Scratch12Float32Array = this.Scratch12Float32Array;
1778
1869
 
1779
1870
  if (value === undefined) {
@@ -1790,7 +1881,7 @@ class Memory {
1790
1881
  Scratch12Float32Array[0x01] = value.y;
1791
1882
  Scratch12Float32Array[0x02] = value.z;
1792
1883
 
1793
- this.write(address, Scratch12Float32Array);
1884
+ void this.write(address, Scratch12Float32Array, force);
1794
1885
 
1795
1886
  return this;
1796
1887
  }
@@ -1799,17 +1890,18 @@ class Memory {
1799
1890
  * Reads or writes an array of Vector3.
1800
1891
  * @param address Address to access.
1801
1892
  * @param lengthOrValues Length to read or array to write.
1893
+ * @param force When writing, if true temporarily changes page protection to allow the write.
1802
1894
  * @returns Array of Vector3 read or this instance if writing.
1803
1895
  * @example
1804
1896
  * ```ts
1805
1897
  * const cs2 = new Memory('cs2.exe');
1806
- * const myVectors = cs2.vector3Array(0x12345678n, 2);
1898
+ * const myVector3s = cs2.vector3Array(0x12345678n, 2);
1807
1899
  * cs2.vector3Array(0x12345678n, [{ x: 1, y: 2, z: 3 }]);
1808
1900
  * ```
1809
1901
  */
1810
1902
  public vector3Array(address: bigint, length: number): Vector3[];
1811
- public vector3Array(address: bigint, values: Vector3[]): this;
1812
- public vector3Array(address: bigint, lengthOrValues: Vector3[] | number): Vector3[] | this {
1903
+ public vector3Array(address: bigint, values: Vector3[], force?: boolean): this;
1904
+ public vector3Array(address: bigint, lengthOrValues: Vector3[] | number, force?: boolean): Vector3[] | this {
1813
1905
  if (typeof lengthOrValues === 'number') {
1814
1906
  const length = lengthOrValues;
1815
1907
  const scratch = new Float32Array(length * 0x03);
@@ -1840,14 +1932,27 @@ class Memory {
1840
1932
  scratch[j + 0x02] = vector3.z;
1841
1933
  }
1842
1934
 
1843
- this.write(address, scratch);
1935
+ void this.write(address, scratch, force);
1844
1936
 
1845
1937
  return this;
1846
1938
  }
1847
1939
 
1940
+ /**
1941
+ * Reads or writes a raw Vector3 as a Float32Array.
1942
+ * @param address Address to access.
1943
+ * @param values Optional Float32Array to write.
1944
+ * @param force When writing, if true temporarily changes page protection to allow the write.
1945
+ * @returns Float32Array read or this instance if writing.
1946
+ * @example
1947
+ * ```ts
1948
+ * const cs2 = new Memory('cs2.exe');
1949
+ * const myVector3 = cs2.vector3Raw(0x12345678n);
1950
+ * cs2.vector3Raw(0x12345678n, new Float32Array([1, 2, 3]));
1951
+ * ```
1952
+ */
1848
1953
  public vector3Raw(address: bigint): Float32Array;
1849
- public vector3Raw(address: bigint, values: Float32Array): this;
1850
- public vector3Raw(address: bigint, values?: Float32Array): Float32Array | this {
1954
+ public vector3Raw(address: bigint, values: Float32Array, force?: boolean): this;
1955
+ public vector3Raw(address: bigint, values?: Float32Array, force?: boolean): Float32Array | this {
1851
1956
  if (values === undefined) {
1852
1957
  return this.f32Array(address, 0x03);
1853
1958
  }
@@ -1856,7 +1961,7 @@ class Memory {
1856
1961
  throw new RangeError('values.length must be 3.');
1857
1962
  }
1858
1963
 
1859
- this.write(address, values);
1964
+ void this.write(address, values, force);
1860
1965
 
1861
1966
  return this;
1862
1967
  }
@@ -1865,6 +1970,7 @@ class Memory {
1865
1970
  * Reads or writes a Vector4 (object with w, x, y, z).
1866
1971
  * @param address Address to access.
1867
1972
  * @param value Optional Vector4 to write.
1973
+ * @param force When writing, if true temporarily changes page protection to allow the write.
1868
1974
  * @returns The Vector4 at address, or this instance if writing.
1869
1975
  * @example
1870
1976
  * ```ts
@@ -1874,42 +1980,57 @@ class Memory {
1874
1980
  * ```
1875
1981
  */
1876
1982
  public vector4(address: bigint): Vector4;
1877
- public vector4(address: bigint, value: Vector4): this;
1878
- public vector4(address: bigint, value?: Vector4): Vector4 | this {
1983
+ public vector4(address: bigint, value: Vector4, force?: boolean): this;
1984
+ public vector4(address: bigint, value?: Vector4, force?: boolean): Vector4 | this {
1879
1985
  // TypeScript is funny sometimes, isn't it?… 🫠…
1880
1986
  if (value === undefined) {
1881
1987
  return this.quaternion(address);
1882
1988
  }
1883
1989
 
1884
- return this.quaternion(address, value);
1990
+ return this.quaternion(address, value, force);
1885
1991
  }
1886
1992
 
1887
1993
  /**
1888
1994
  * Reads or writes an array of Vector4.
1889
1995
  * @param address Address to access.
1890
1996
  * @param lengthOrValues Length to read or array to write.
1997
+ * @param force When writing, if true temporarily changes page protection to allow the write.
1891
1998
  * @returns Array of Vector4 read or this instance if writing.
1892
1999
  * @example
1893
2000
  * ```ts
1894
2001
  * const cs2 = new Memory('cs2.exe');
1895
- * const myVectors = cs2.vector4Array(0x12345678n, 2);
2002
+ * const myVector4s = cs2.vector4Array(0x12345678n, 2);
1896
2003
  * cs2.vector4Array(0x12345678n, [{ w: 1, x: 0, y: 0, z: 0 }]);
1897
2004
  * ```
1898
2005
  */
1899
2006
  public vector4Array(address: bigint, length: number): Vector4[];
1900
- public vector4Array(address: bigint, values: Vector4[]): this;
1901
- public vector4Array(address: bigint, lengthOrValues: Vector4[] | number): Vector4[] | this {
2007
+ public vector4Array(address: bigint, values: Vector4[], force?: boolean): this;
2008
+ public vector4Array(address: bigint, lengthOrValues: Vector4[] | number, force?: boolean): Vector4[] | this {
1902
2009
  // TypeScript is funny sometimes, isn't it?… 🫠…
1903
2010
  if (typeof lengthOrValues === 'number') {
1904
2011
  return this.quaternionArray(address, lengthOrValues);
1905
2012
  }
1906
2013
 
1907
- return this.quaternionArray(address, lengthOrValues);
2014
+ return this.quaternionArray(address, lengthOrValues, force);
1908
2015
  }
1909
2016
 
1910
2017
  public vector4Raw(address: bigint): Float32Array;
1911
- public vector4Raw(address: bigint, values: Float32Array): this;
1912
- public vector4Raw(address: bigint, values?: Float32Array): Float32Array | this {
2018
+ /**
2019
+ * Reads or writes a raw Vector4 as a Float32Array.
2020
+ * @param address Address to access.
2021
+ * @param values Optional Float32Array to write.
2022
+ * @param force When writing, if true temporarily changes page protection to allow the write.
2023
+ * @returns Float32Array read or this instance if writing.
2024
+ * @example
2025
+ * ```ts
2026
+ * const cs2 = new Memory('cs2.exe');
2027
+ * const myVector4 = cs2.vector4Raw(0x12345678n);
2028
+ * cs2.vector4Raw(0x12345678n, new Float32Array([1, 0, 0, 0]));
2029
+ * ```
2030
+ */
2031
+ public vector4Raw(address: bigint): Float32Array;
2032
+ public vector4Raw(address: bigint, values: Float32Array, force?: boolean): this;
2033
+ public vector4Raw(address: bigint, values?: Float32Array, force?: boolean): Float32Array | this {
1913
2034
  if (values === undefined) {
1914
2035
  return this.f32Array(address, 0x04);
1915
2036
  }
@@ -1918,7 +2039,7 @@ class Memory {
1918
2039
  throw new RangeError('values.length must be 4.');
1919
2040
  }
1920
2041
 
1921
- this.write(address, values);
2042
+ void this.write(address, values, force);
1922
2043
 
1923
2044
  return this;
1924
2045
  }