Skip to content

Lua API Reference

xAstroBoy edited this page Apr 14, 2026 · 2 revisions

Lua API Reference

This is the complete API reference for Quest UE4 Modloader's Lua scripting environment.

For the full detailed reference, see docs/LUA_API.md

Table of Contents

  1. Logging
  2. Object Finding
  3. UObject Methods
  4. ProcessEvent Hooks
  5. Native Hooks
  6. Memory Read/Write
  7. Timers & Delayed Actions
  8. Structs (LuaUStruct)
  9. TArray
  10. Enums
  11. Widget Creation
  12. Config & File I/O
  13. Cross-Mod Communication
  14. Bridge Commands

1. Logging

Log("Info message")
LogWarn("Warning message")
LogError("Error message")
print("Debug", 42, true, obj)  -- Auto-formats all types
Notify("Title", "Body")       -- In-game notification

2. Object Finding

-- Most commonly used:
local obj = FindFirstOf("ClassName")       -- First live instance
local all = FindAllOf("ClassName")          -- All live instances (table)

-- Advanced:
local cls = FindClass("ClassName")          -- UClass object
local obj = FindObject("ShortName")         -- By short name
local obj = StaticFindObject("FullPath")    -- By full path
local obj = LoadAsset("/Game/Path/Asset")   -- Load from PAK
local world = GetWorldContext()             -- Current UWorld

3. UObject Methods

Every UObject returned by the API has these methods:

obj:IsValid()          -- Is this object still alive?
obj:GetName()          -- Short name (e.g., "PlayerController_0")
obj:GetFullName()      -- Full path
obj:GetClass()         -- UClass object
obj:GetClassName()     -- Class name string

-- Property access (reflection)
obj:Get("PropName")    -- Read property
obj:Set("PropName", v) -- Write property
obj.PropName           -- Shorthand read
obj.PropName = v       -- Shorthand write

-- Function calls
obj:Call("FuncName", arg1, arg2, ...)
obj:FuncName(arg1, arg2, ...)  -- Shorthand

-- Type checking
UObject_IsA(obj, "ClassName")  -- Inheritance check

4. ProcessEvent Hooks

-- Pre-hook: fires BEFORE original. Return "BLOCK" to prevent it.
RegisterPreHook("/Script/Game.Class:Function", function(self, func, parms)
    local obj = self:get()
    return "BLOCK"  -- Optional: skip original
end)

-- Post-hook: fires AFTER original.
RegisterPostHook("/Script/Game.Class:Function", function(self, func, parms)
    local obj = self:get()
    WriteU8(parms, 0)  -- Modify return value
end)

-- Combined (returns IDs for removal)
local preId, postId = RegisterHook("Class:Func", function(self, parms) end)
UnregisterHook("Class:Func", preId, postId)

Hook Paths

Function paths follow UE4's naming:

  • Blueprint: /Game/Blueprints/Path/BP.BP_C:FunctionName
  • Native: /Script/ModuleName.ClassName:FunctionName

5. Native Hooks

-- Hook by C++ symbol name
RegisterNativeHook("_ZN9SomeClass4FuncEv", "fp",
    function(thisPtr) end,           -- Pre-hook
    function(thisPtr, retval) end    -- Post-hook
)

-- Hook by address
local base = GetLibBase()
RegisterNativeHookAt(Offset(base, 0x1234), "vpp",
    function(a1, a2) return "BLOCK" end,
    nil
)

-- Call native function
local result = CallNativeBySymbol("_ZSymbol", "ip", ptr)
local result = CallNative(addr, "fp", ptr)

Signature format: First char = return type, rest = arg types. v=void, i=int32, u=uint32, b=bool, p=pointer, f=float, d=double, l=int64

6. Memory Read/Write

⚠️ Only use for byte/instruction patching. For UObject properties, use Get/Set.

ReadU8(addr)  / WriteU8(addr, val)    -- 8-bit
ReadU16(addr) / WriteU16(addr, val)   -- 16-bit
ReadU32(addr) / WriteU32(addr, val)   -- 32-bit
ReadU64(addr) / WriteU64(addr, val)   -- 64-bit
ReadS32(addr) / WriteS32(addr, val)   -- Signed 32-bit
ReadFloat(addr) / WriteFloat(addr, v) -- Float

-- Address helpers
local base = GetLibBase()              -- Game library base
local sym = FindSymbol("name")         -- dlsym resolve
local sym = Resolve("name")            -- Full resolution chain
local pat = FindPattern("FF 43 ?? ??") -- Byte pattern scan
local ptr = Offset(base, 0x1000)       -- Pointer arithmetic
IsNull(ptr)                            -- NULL check
IsValidPtr(ptr)                        -- Mapped check

7. Timers & Delayed Actions

-- One-shot timer
local h = ExecuteWithDelay(5000, function() end)

-- Next tick
ExecuteAsync(function() end)

-- Repeating timer
local h = LoopAsync(2000, function() end)

-- Game thread variants (safe for UObject modification)
ExecuteInGameThread(function() end)
ExecuteInGameThreadWithDelay(1000, function() end)
LoopInGameThread(2000, function() end)

-- Frame-based timers
ExecuteWithDelayFrames(60, function() end)
LoopAsyncFrames(1, function() end)  -- Every frame

-- Cancel
CancelDelayedAction(h)
IsDelayedActionValid(h)

8. Structs

Struct properties (FVector, FRotator, IntPoint, etc.) are returned as LuaUStruct userdata:

local pos = actor:Get("Position")  -- LuaUStruct

-- Field access
pos.X                              -- Read field
pos.X = 100                        -- Write field (writes to live memory)

-- Set from table
actor:Set("Position", {X=100, Y=200, Z=300})

-- Pass struct to Call()
actor:Call("SetActorLocation", {X=100, Y=200, Z=300})

-- Methods
pos:GetTypeName()     -- "FVector"
pos:GetSize()         -- Struct size in bytes
pos:Clone()           -- Independent copy
pos:CopyFrom({X=1})   -- Copy from table
pos:GetFields()       -- {X="float", Y="float", Z="float"}
tostring(pos)         -- "UStruct(FVector: X=100, Y=200, Z=300)"

9. TArray

TArray properties are returned as userdata with 1-based indexing:

local arr = obj:Get("SomeArray")

arr[1]                -- First element (1-indexed!)
arr[3] = newValue     -- Write element
#arr                  -- Length
arr:GetArrayNum()     -- Element count
arr:IsEmpty()         -- True if empty
arr:ForEach(function(i, elem)
    Log(i .. ": " .. tostring(elem))
    return false  -- Return true to break
end)
arr:Add(value)        -- Append element
arr:Clear()           -- Remove all

10. Enums

-- Global enum table (auto-populated from reflection)
Enums.ECollisionChannel          -- {ECC_WorldStatic=0, ...}
Enums.DebugMenuType              -- {NewEnumerator5=0, ...}

-- Lookup
local ue = FindEnum("EnumName")
local t = GetEnumTable("EnumName")    -- {Name=Value, ...}
local names = GetEnumNames()           -- All enum names

-- Extend (runtime, adds to UEnum metadata)
AppendEnumValue("EnumName", "NewValue", 99)

11. Widget Creation

local widget = CreateWidget("TextBlock")
local vbox = CreateWidget("VerticalBox")
local custom = CreateWidget("MyWidget_C")

-- With owning player
local pc = FindFirstOf("PlayerController")
local w = CreateWidget("TextBlock", pc)

12. Config & File I/O

-- ModConfig (JSON, persistent)
ModConfig.Save("ModName", {key = "value", num = 42})
local cfg = ModConfig.Load("ModName")
local path = ModConfig.GetPath("ModName")

-- Raw file I/O
local text = ReadTextFile("/path/to/file")
WriteTextFile("/path/to/file", "content")
FileExists("/path/to/file")

-- Mod paths
GetModDir()   -- This mod's directory
GetDataDir()  -- Shared data directory

13. Cross-Mod Communication

-- SharedAPI table (shared across all mods)
SharedAPI.MyMod = { DoSomething = function() end }

-- Shared variables
SetSharedVariable("key", value)
local v = GetSharedVariable("key")

14. Bridge Commands

RegisterBridgeCommand("my_command", function(args)
    return { status = "ok", data = 42 }
end)

Test: python tools/deploy.py consolemy_command

Clone this wiki locally