gurp logo gurp docs

Production Reference

gurp Lua API Reference

Verified against runtime bindings in publish_gurp_api(lua_State* L) and underlying implementation paths.

Overview

overviewcore

This page documents the currently exported Lua API from the native runtime.

API bindings can change after loader updates. Guard scripts with gurp.api_version checks when possible.

Quick Nav

  • gurp top-level runtime + helpers
  • gurp.memory raw memory read/write
  • gurp.sdk object, attribute, and value APIs
  • gurp.cache custom player feed
  • gurp.ui script UI builder
  • gurp.draw overlay draw commands

Safety Notes

  • Object args are raw u64 addresses and can become stale.
  • Prefer exact attribute matching for writes in production.
  • Long waits can abort with "Lua environment reset".

Version / Runtime Notes

metacompat

  • Current marker: gurp.api_version == 3
  • Cache marker: gurp.has_cache_api == true
  • Script reset increments runtime generation and cancels active wait loops.
  • gurp.game is populated at publish time (snapshot semantics).
Use pcall around long-running loops if your workflow includes manual resets.

Top-Level Fields

metafields

gurp.api_version   -> integer (3)
gurp.has_cache_api -> boolean (true)
gurp.memory         -> table
gurp.sdk            -> table
gurp.cache          -> table
gurp.ui             -> table
gurp.draw           -> table
gurp.game           -> table
Check version and module fields before running shared scripts across builds.

Namespace: gurp

apiruntime

Function Summary

FunctionReturnsNotes
get_base_address()u64Can be 0
get_datamodel()u64Can be 0
get_workspace()u64Can be 0
get_camera()u64Can be 0
get_localplayer()u64Can be 0
get_offset(ns,name)u64|nilNil if missing/invalid
wait(seconds)nilDefault 0, clamp 0..60
sleep_ms(ms)nilDefault 0, clamp 0..60000
time_ms()u64GetTickCount64
is_key_down(vk)boolDefault vk 0
log(msg)nilNo-op if msg invalid
clamp(v,min,max)f32All defaults 0
wait and sleep_ms can raise "Lua environment reset" when runtime generation changes.

Example

if gurp.api_version >= 3 then
  local dm = gurp.get_datamodel()
  gurp.log("datamodel = " .. tostring(dm))
end

gurp.memory

modulememory

FunctionReturnsNotes
read_u64(addr)u64|nilNil on invalid/read fail
read_u32(addr)u32|nilNil on invalid/read fail
read_f32(addr)f32|nilNil on invalid/read fail
read_bool(addr)bool|nilNil on invalid/read fail
write_u64(addr,v)boolFalse on invalid/write fail
write_u32(addr,v)boolValue cast from u64 arg
write_f32(addr,v)boolDefault value 0.0
write_bool(addr,v)boolLua truthy conversion
All operations guard address validity before remote access.
Safe usage: read first, validate type/range, then write.

Example

local hp = gurp.memory.read_f32(humanoid_addr + 0x194)
if hp ~= nil and hp > 1 then
  gurp.memory.write_f32(humanoid_addr + 0x194, hp - 1)
end

gurp.sdk (Object Helpers)

moduleobjects

All object arguments are expected to be u64 addresses.

Identity & Hierarchy

name(obj) -> string|nil
display_name(obj) -> string|nil
class_name(obj) -> string|nil
children(obj) -> table<u64>
find_child(obj, child_name) -> u64|nil
find_child_of_class(obj, class_name) -> u64|nil
character(obj) -> u64|nil

Spatial & State

position(obj) -> vec3|nil
velocity(obj) -> vec3|nil
size(obj) -> vec3|nil
humanoid_state(obj) -> u32|nil
text(obj) -> string|nil
anchored(obj) -> bool|nil
set_anchored(obj, bool) -> bool
set_can_collide(obj, bool) -> bool

Transforms & Camera

field_of_view(camera) -> f32|nil
set_field_of_view(camera, fov=70) -> bool
cframe(obj) -> cframe|nil
rotation(obj) -> matrix3|nil
camera_rotation(obj) -> matrix3|nil
camera_position(obj) -> vec3|nil
set_rotation(obj, matrix3) -> bool
set_camera_rotation(obj, matrix3) -> bool

Attribute APIs

attribute_instance(obj) -> u64|nil
attribute_entry(obj, name) -> u64|nil
attribute_value_ptr(obj, name) -> u64|nil
attribute_f32(obj, name, fallback=0.0) -> f32
attribute_bool(obj, name, fallback=false) -> bool
attribute_dump(obj, max=32) -> table|nil
attribute_values(obj, max=64) -> table|nil
attribute_find(obj, query, contains=true, max=256) -> table|nil
attribute_set_f32(obj, query, value, contains=true, max=256) -> bool
attribute_set_bool(obj, query, value, contains=true, max=256) -> bool
attribute_set_u32(obj, query, value, contains=true, max=256) -> bool

Value + Misc

value_u64/u32/f32/bool(obj) -> typed|nil
set_value_u64/u32/f32/bool(obj, value) -> bool
primitive(obj) -> u64|nil
primitive_flags(obj) -> u64|nil
background_color3(obj) -> vec3|nil
players_service() -> u64|nil
Note: some valid no-match paths return numeric 0 (not nil), especially in find/lookup style APIs.

Example

local lp = gurp.get_localplayer()
local ch = gurp.sdk.character(lp)
if ch and ch ~= 0 then
  local hrp = gurp.sdk.find_child(ch, "HumanoidRootPart")
  if hrp and hrp ~= 0 then
    local p = gurp.sdk.position(hrp)
    gurp.log(("HRP: %.1f %.1f %.1f"):format(p.x, p.y, p.z))
  end
end

gurp.cache (Custom Player Feed)

modulecache

Lifecycle

add_player(
  address:u64,
  userid:u64,
  name:string,
  display_name:string,
  team_address:u64,
  health:number=100.0,
  max_health:number=100.0
) -> boolean

remove_player(userid:u64, address:u64) -> boolean
clear_players() -> boolean
players_count() -> integer

Per-Player Updates

set_player_part(userid, address, part_name, part_address) -> boolean
set_player_humanoid(userid, address, humanoid_address) -> boolean
set_player_health(userid, address, health, max_health) -> boolean
Keep userid + address pairs consistent. Most cache desync bugs come from mixing one and not the other.

Example

gurp.cache.add_player(0, 12345, "alpha", "Alpha", 0, 100, 100)
gurp.log("cache count: " .. tostring(gurp.cache.players_count()))

gurp.ui (Lua UI Builder)

moduleui

Element Creation

window(window_id, title, x=100, y=100, width=300, height=180) -> bool
text(window_id, element_id, text) -> bool
button(window_id, element_id, label) -> bool
checkbox(window_id, element_id, label, default=false) -> bool
slider_float(window_id, element_id, label, min=0, max=1, default=min) -> f32

State Access & Window Controls

get_bool(window_id, element_id) -> bool
set_bool(window_id, element_id, value) -> bool
get_float(window_id, element_id) -> f32
set_float(window_id, element_id, value) -> bool

remove_window(window_id) -> bool
clear() -> bool

set_interactive(enabled) -> bool
get_interactive() -> bool

set_draggable(window_id, enabled) -> bool
get_draggable(window_id) -> bool
  • window_id + element_id act as retained state keys.
  • Button returns true once per click cycle (latched behavior).
  • get_draggable returns true if window does not exist.
Keep IDs stable between script updates; changing IDs resets saved UI state and confuses users.

Example

gurp.ui.window("main", "Main", 120, 120, 360, 220)
local enabled = gurp.ui.checkbox("main", "esp", "ESP", false)
if gurp.ui.button("main", "panic", "Panic") then
  gurp.ui.clear()
end

gurp.draw (Overlay Drawlist API)

modulerender

Primitives

clear() -> bool
text(
  x:number, y:number, text:string,
  r:number=1, g:number=1, b:number=1, a:number=1,
  centered:boolean=false
) -> bool

line(
  x1:number, y1:number, x2:number, y2:number,
  thickness:number=1,
  r:number=1, g:number=1, b:number=1, a:number=1
) -> bool

circle(
  x:number, y:number,
  radius:number,
  thickness:number=1,
  segments:integer=0,
  r:number=1, g:number=1, b:number=1, a:number=1
) -> bool

circle_filled(
  x:number, y:number,
  radius:number,
  segments:integer=0,
  r:number=1, g:number=1, b:number=1, a:number=1
) -> bool

Projection Helper

world_to_screen(x:number, y:number, z:number)
  -> {x:number, y:number} | nil
Typical render loop calls gurp.draw.clear() each tick before redraw. Resetting the Lua environment clears draw commands.
If text/lines look offset, verify your world_to_screen output before tweaking draw coordinates manually.

Example

local p = gurp.draw.world_to_screen(0, 5, 0)
if p then
  gurp.draw.text(p.x, p.y, "target", 1, 0.2, 0.2, 1, true)
end

gurp.game Snapshot Table

statesnapshot

gurp.game.is_in_game    -> boolean
gurp.game.base_address  -> u64
gurp.game.datamodel     -> u64
gurp.game.workspace     -> u64
gurp.game.camera        -> u64
gurp.game.localplayer   -> u64
This table is a startup snapshot. If you need fresh values mid-session, call top-level getters again.

Attribute Cookbook

guideattributes

Discovery

  • attribute_dump(obj, max=32): returns {name, entry, value_ptr} list.
  • attribute_values(obj, max=64): includes interpreted f32/i32/u32/u64/bool.
  • attribute_find(obj, query, contains=true, max=256): first match table or nil.

Read APIs

  • attribute_f32 and attribute_bool return fallback, never nil.
  • attribute_entry/attribute_value_ptr can return 0 on miss.
  • Use exact names for stable reads where possible.

Write APIs

  • attribute_set_f32/bool/u32 use verification reads.
  • Exact mode (contains=false) should be your default in real scripts.
  • u32 writer can use double-based path on matching layouts.

Value Slot APIs

value_u64/u32/f32/bool(obj) -> typed|nil
set_value_u64/u32/f32/bool(obj, value) -> bool

Use these for instances where Offsets::Misc::Value is the live backing value.

Robust Multi-Pass Pattern

local function safe_set_attr_u32(obj, exact_name, value)
  if gurp.sdk.attribute_set_u32(obj, exact_name, value, false, 256) then
    return true
  end

  local vals = gurp.sdk.attribute_values(obj, 256)
  if not vals then return false end

  for _, it in ipairs(vals) do
    if it.name and it.name:lower() == exact_name:lower() then
      return gurp.sdk.attribute_set_u32(obj, it.name, value, false, 512)
    end
  end

  return gurp.sdk.attribute_set_u32(obj, exact_name, value, true, 512)
end
If reads change but gameplay does not, you likely hit a non-live candidate slot. Validate against behavior, not readback alone.

Troubleshooting

opsdebug

  • Returns nil: invalid object/address, bad arg type, failed guarded read, or failed world projection.
  • Stale pointers: refresh pointers after respawn/teleport/state transitions.
  • Reset error: "Lua environment reset" means runtime generation changed mid-execution.
  • Reads change but game does not: choose correct live attribute slot or use value APIs.
  • Contains vs exact: use exact for production writes, contains only as fallback.
  • Loop perf: avoid full attribute scans every tick, cache carefully and revalidate.

Coverage Report

auditsource

This reference covers all functions exported in publish_gurp_api(lua_State* L) for:

  • gurp
  • gurp.memory
  • gurp.sdk (including attribute APIs and value APIs)
  • gurp.cache
  • gurp.ui
  • gurp.draw
  • gurp.game snapshot fields
Potential ambiguity to keep in mind: some successful lookups may return 0 (u64) instead of nil when no child/object is found.