> ## Documentation Index
> Fetch the complete documentation index at: https://docs.spurdoverse.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Memory

> Game modules, pattern scans and struct layouts.

Finds modules and byte patterns in the game process and defines struct layouts to read with. The reading itself is done through [Pointer](/api/types/pointer).

```ts theme={null}
import memory from "@native/memory";
```

<Note>
  Game memory is read-only, there is no write API. No manifest permission is needed.
</Note>

## Overview

<CardGroup cols={2}>
  <Card title="Modules" icon="cube" href="#modules">
    `module`.
  </Card>

  <Card title="Pattern scans" icon="magnifying-glass" href="#pattern-scans">
    `scan`, `scanAll`, pattern syntax.
  </Card>

  <Card title="Structs" icon="table-cells" href="#structs">
    `struct`, `union`.
  </Card>
</CardGroup>

***

## Modules

### module

<br />

```ts theme={null}
memory.module(name: string): ModuleInfo | null
```

A loaded module by file name, case-insensitive, as `{ name, base, size }`, or `null`. Only `client.dll`, `engine2.dll`, `inputsystem.dll`, `matchmaking.dll` and `soundsystem.dll` are available.

```ts theme={null}
const client = memory.module("client.dll");
if (client) console.log(`${client.name} at ${client.base}, ${client.size} bytes`);
```

`name` is lower-case, `base` is a [Pointer](/api/types/pointer), `size` is the image size in bytes.

***

## Pattern scans

Patterns are IDA-style: hex bytes separated by spaces, `?` or `??` for any byte.

```ts theme={null}
"48 8B 05 ? ? ? ? 48 85 C0"
"E8 ?? ?? ?? ?? 48 8B D8"
```

Scans are slow. Scan once at load, not every tick.

### scan

<br />

```ts theme={null}
memory.scan(module: string, pattern: string): Pointer | null
```

The first match, or `null` when there's none. Throws `ENOENT` when the module isn't loaded.

```ts theme={null}
const hit = memory.scan("client.dll", "48 8B 05 ? ? ? ? 48 85 C0");
const target = hit && hit.add(7).add(hit.add(3).read("int32"));   // rip-relative
```

### scanAll

<br />

```ts theme={null}
memory.scanAll(module: string, pattern: string): Pointer[]
```

Every match in address order, `[]` when none.

```ts theme={null}
const calls = memory.scanAll("client.dll", "E8 ? ? ? ? 48 8B D8");
console.log(calls.length, calls[0]);
```

***

## Structs

### struct

<br />

```ts theme={null}
memory.struct(name: string, fields: FieldDefs): StructType
memory.struct(fields: FieldDefs): StructType
```

Defines a C layout to read with [Pointer.read](/api/types/pointer#read) or [Snapshot.as](/api/types/pointer#snapshot), laid out in field order with C alignment. Same as [ffi.struct](/api/ffi#struct), without needing the `ffi` permission.

```ts theme={null}
const Vec3 = memory.struct("Vec3", { x: "float", y: "float", z: "float" });
const Bone = memory.struct({ pos: Vec3, scale: "float", rot: "quaternion" });

const bones = boneArray.read(Bone, 128);
console.log(bones[0].pos.x, bones[0].rot);
```

Field types are the [scalar types](/api/types/pointer#scalar-types), C names (`"DWORD"`, `"void*"`), arrays (`"float[16]"`, `"Vec3[4]"`, `"char[32]"`) or another struct. A named struct can be used by name in later definitions. In game memory `ptr` fields read as `Pointer`.

<Warning>
  `"string"` and `"char*"` fields are pointers, not text. Follow them with `view.name.read("string")`.
  Inline text is `"char[N]"`.
</Warning>

### union

<br />

```ts theme={null}
memory.union(name: string, fields: FieldDefs): UnionType
memory.union(fields: FieldDefs): UnionType
```

Same as `struct`, but every field starts at offset 0.

```ts theme={null}
const Value = memory.union({ i: "int32", f: "float", p: "ptr" });
const v = slot.read(Value);
console.log(v.i, v.f, v.p);
```

***

## Example

Finds a global through a signature once, then reads it every tick.

```ts theme={null}
import memory from "@native/memory";

const Globals = memory.struct({
    realTime: "float",
    frameCount: "int32",
    absFrameTime: "float",
});

const hit = memory.scan("client.dll", "48 8B 05 ? ? ? ? 48 85 C0");
const slot = hit && hit.add(7).add(hit.add(3).read("int32"));

on("tick", () => {
    if (!slot) return;
    try {
        const globals = slot.deref().read(Globals);
        console.log(globals.frameCount, globals.realTime.toFixed(2));
    } catch (e) {
        if ((e as { code?: string }).code !== "EREAD") throw e;
    }
});
```
