Types and assets
Reading the game’s own structs by name, replacing what it loads, and taking input without learning a scancode.
Named access to the game's own structures. This is how a mod reads a field nobody wrote a question for.
Look up a struct the pack declared.
Name, kind and offset of every mapped field.
Declared size in bytes.
Map a raw value to its name, so a panel shows “Red” rather than 2.
And back, so a filter compares against “Red” without the mod learning the number.
Where the names come from
The pack’s layout file. A mod names fields; the pack maps them per build.
[struct.Player] size = 0x4A0 health = { at = 0x120, kind = "f32" } mana = { at = 0x124, kind = "f32" } team = { at = 0x1A4, kind = "enum", enum = "Team" }
Reading and writing those fields on a live instance. A sharper tool than the rest of the surface, so it is gated separately.
Read one field by name.
auto mana = f.types().of("Player").field<float>("mana"); if (mana.failed()) log.warn("mana moved on this build: {}", mana.detail());
Write it back.
A mod holding 0x124 reads garbage after the next patch and never
tells anyone. A mod holding "mana" gets a
Failed the moment the pack stops mapping it, which is loud,
correct, and fixed by updating one pack. Using this does make a mod
game-specific.
Replacing what the game loads, by logical path, without touching a single file on disk.
Replace an asset. The pack maps the logical path onto whatever the game actually does: a loose file, a pak entry, a resource blob, a JAR entry.
textures/player/base.pngLayer a whole directory by matching paths.
Drop your layer for one asset.
What exists, for a mod that wants to show the user a picker.
Ask the engine to re-read. Frequently denied, and the capability says so rather than pretending.
restore drops a layer, and unloading drops a mod’s layers automaticallypre-init it is seen; at runtime it applies next load, which for a loaded texture may be a level changeKeybinds the user can rebind, and exclusive capture when you need the keys.
Declare a bind. You never read a scancode, which is why rebinding works without the mod knowing.
toggle_ = f.input().bind("toggle", "F7");Edge, this frame.
Level.
Analogue, where the backend exposes it.
Exclusive input. The game stops seeing it until the token drops.
{ auto tok = f.input().capture(CaptureScope::Keyboard); // game sees nothing while tok is alive } // released here, deterministically
A mod that takes capture and never releases makes the game stop responding to
keys, and nothing about that is self-explanatory. The overlay’s
capture command names the holder, and the overlay’s own
capture always releases on Escape.