Skip to content

Augment.Mixin

Augment.Mixin is the low-level interface to the hook engine. It is available when you need:

  • Priority and tag control over hook registrations
  • Direct function invocation by symbol name
  • Raw memory read/write on game objects
  • Symbol address resolution

Loading#

local Mixin = require("Augment.Mixin")
import * as Mixin from "Augment.Mixin"

Hook registration#

Mixin.register(symbol, phase, fn, priority?, tag?)#

Registers fn as a hook on symbol.

Parameter Type Description
symbol string Flat or mangled symbol name (e.g. "Foo::bar")
phase "before" | "after" | "replace" When to fire
fn function(ctx) The hook callback
priority number (optional) Execution order within the phase, lower = earlier. Default 0
tag string (optional) Debug label visible in inspect() output

Returns true on success, false if the symbol was not found.

local ok = Mixin.register("Foo::bar", "before", function(ctx)
    print("before bar")
end, -5, "my-mod:foo")
const ok = Mixin.register("Foo::bar", "before", (ctx) => {
    print("before bar")
}, -5, "my-mod:foo")

Mixin.builder(symbol)#

Returns a raw builder object (internal, prefer Augment.Hook).


Direct calls#

Mixin.call(symbol, kinds, values)#

Invokes a game function by symbol name, bypassing any registered hooks.

Parameter Type Description
symbol string Symbol name
kinds string[] Type descriptor for each argument ("ptr", "f32", "i32", etc.)
values any[] Argument values
-- Call Foo::doThing(self*, int count)
local self_ptr = Mixin.resolve("Foo::singleton")
Mixin.call("Foo::doThing", {"ptr", "i32"}, {self_ptr, 5})
// Call Foo::doThing(self*, int count)
const selfPtr = Mixin.resolve("Foo::singleton")
Mixin.call("Foo::doThing", ["ptr", "i32"], [selfPtr, 5])

Symbol resolution#

Mixin.resolve(symbol) → lightuserdata | nil#

Returns the runtime address of symbol as an opaque pointer, or nil if not found.

local addr = Mixin.resolve("daCow_c::action_angry")
if addr then
    print("found at", addr)
end
const addr = Mixin.resolve("daCow_c::action_angry")
if (addr) {
    print("found at", addr)
}

Mixin.cstr(s) → lightuserdata#

Copies the Lua string s into a persistent null-terminated C buffer and returns its address. Useful when a game function expects a const char* that must outlive the call.

local tag = Mixin.cstr("my-tag")
Mixin.call("Logger::setTag", {"ptr"}, {tag})
const tag = Mixin.cstr("my-tag")
Mixin.call("Logger::setTag", ["ptr"], [tag])

Memory access#

These functions read and write raw memory at a pointer + byte offset.

Kind descriptors#

Kind C type Size
"u8" uint8_t 1 byte
"i8" int8_t 1 byte
"u16" uint16_t 2 bytes
"i16" int16_t 2 bytes
"u32" uint32_t 4 bytes
"i32" int32_t 4 bytes
"u64" uint64_t 8 bytes
"i64" int64_t 8 bytes
"f32" float 4 bytes
"f64" double 8 bytes
"ptr" void* pointer-sized
"pmf" pointer-to-member-fn pointer-sized

Mixin.read(ptr, offset, kind) → number | lightuserdata#

Reads a scalar value at ptr + offset.

local hp = Mixin.read(enemy_ptr, 0x10, "f32")
const hp = Mixin.read(enemyPtr, 0x10, "f32")

Mixin.write(ptr, offset, kind, value)#

Writes a scalar value at ptr + offset.

Mixin.write(enemy_ptr, 0x10, "f32", 9999.0)  -- set HP to max
Mixin.write(enemyPtr, 0x10, "f32", 9999.0)  // set HP to max

Mixin.read_str(ptr, offset, len) → string#

Reads a null-terminated (or len-capped) string from memory.

local name = Mixin.read_str(obj_ptr, 0x04, 32)
const name = Mixin.read_str(objPtr, 0x04, 32)

Mixin.write_str(ptr, offset, len, s)#

Writes a string into a fixed-length buffer (null-terminates, truncates to len - 1).

Mixin.write_str(obj_ptr, 0x04, 32, "NewName")
Mixin.write_str(objPtr, 0x04, 32, "NewName")

Hook-context argument access#

These functions only work inside a hook callback.

Mixin.arg(index, kind) → value#

Reads the index-th argument of the currently-executing hook call.

Mixin.register("Foo::bar", "before", function(ctx)
    local first_arg = Mixin.arg(0, "f32")
end)
Mixin.register("Foo::bar", "before", (ctx) => {
    const firstArg = Mixin.arg(0, "f32")
})

Mixin.set_arg(index, kind, value)#

Overwrites the index-th argument.

Mixin.set_arg(0, "f32", 999.0)
Mixin.set_arg(0, "f32", 999.0)

Info

Prefer named fields on ctx (e.g. ctx.amount) over Mixin.arg.