Agent & LLM API Guide
Runtime: LuaJIT 2.1 (Lua 5.1 syntax).
Execution Context: In-process synchronous execution on the game thread inside CS:GO’s frame loop.
This guide provides autonomous AI agents and language models with the exact specifications, constraints, API signatures, and code generation patterns required to write reliable Lua scripts for Aimsense.
1. Safety Rules & Execution Invariants
Section titled “1. Safety Rules & Execution Invariants”When writing code for Aimsense, agents must adhere to these invariants:
- Guarded Entity Resolution: Never assume entity lookups return valid objects. Always guard checks:
local local_player = entity.get_local_player()if not local_player or not local_player:is_alive() then return end
- Strict Render Callback Boundary: All
render.*functions are only valid inside therendercallback. Calling render methods from any other callback will corrupt graphics state or fail silently. - 0-Based Unbounded Netprop Arrays: Netprop arrays (such as
player.m_hMyWeapons) are 0-indexed memory wrappers with no length bounds. Never use the Lua#length operator on netprop arrays. Index from0tomax_size - 1. - Explicit Returns in
draw_chams:return 0: Custom takeover mode. The script is responsible for callingmaterials.draw_chams(mat).return 1: Passthrough mode. Engine draws the model normally.- Omitting
returnevaluates to0, hiding the model.
- No Synchronous I/O in Per-Frame Callbacks: Never call blocking network requests (
network.getwithout callback), file decoders, or archive decompressions insiderenderorcreatemove. - No Standard
ioLibrary: Standard Luaio.*is disabled. Use thefilesanddatabasenamespaces. - JSON Userdata Constraints: Userdata objects (
vector,qangle,color) serialize asnullinjson.stringify. Always convert them to plain tables:{ x = v.x, y = v.y, z = v.z }.
2. Event Callbacks Table (client.add_callback)
Section titled “2. Event Callbacks Table (client.add_callback)”| Event Name | Signature | Description |
|---|---|---|
render |
fn() |
Primary visual drawing phase. |
createmove |
fn(cmd: user_cmd_t) |
Pre-aimbot tick processing. Writes to cmd are active. |
post_createmove |
fn(cmd: user_cmd_t) |
Post-engine tick processing. Read-only snapshot. |
antiaim |
fn(ctx: antiaim_context_t) |
Override anti-aim pitch, yaw, desync, and fake lag. |
frame_stage |
fn(stage: number) |
Stages: 0=START, 1=NET_START, 4=NET_END, 5=RENDER_START. |
game_events |
fn(event: game_event_t) |
CS:GO gameplay events (player_death, player_hurt, etc.). |
aim_shot |
fn(shot: shot_t) |
Ragebot client firing intent. |
aim_ack |
fn(shot: shot_t) |
Server shot acknowledgement (hit/miss/spread). |
draw_chams |
fn(class: number) -> number |
Custom chams override. Classes: 0=Enemy, 1=Shot, 2=Backtrack, 3=Local, 4=ViewModel. Return 0 or 1. |
unload |
fn() |
Cleanup hook (restore ConVars, release materials). |
3. Core API Namespaces
Section titled “3. Core API Namespaces”globals (Read-only Table)
Section titled “globals (Read-only Table)”globals.curtime: Current simulation time in seconds.globals.realtime: Wall-clock time since game start.globals.frametime: Duration of last frame in seconds.globals.tickinterval: Seconds per tick (1/64or1/128).globals.tickcount: Current tick count integer.globals.is_in_game:trueif connected and spawned in a server.globals.max_players: Maximum player slots on server.
Global Helper Functions
Section titled “Global Helper Functions”print(val): Log string to cheat console with script prefix.error(msg): Log red error to console (non-terminating).print_raw(text, color?): Unprefixed console output with\aRRGGBBsupport.to_ticks(sec)/to_time(ticks): Time/tick conversions.math.angle_diff(a, b): Shortest signed angle difference in degrees.math.normalize_yaw(yaw): Wraps yaw into[-180, 180].
client
Section titled “client”client.add_callback(event: string, fn: function)client.remove_callback(event: string, fn: function) -> booleanclient.delay_call(seconds: number, fn: function, ...args)client.unload_script()/client.reload_script()client.color_log(r: number, g: number, b: number, ...)
entity
Section titled “entity”entity.get(index: number, is_userid?: boolean) -> entity_t | player_t | weapon_t | nilentity.from_handle(handle: number) -> entity_t | player_t | weapon_t | nilentity.get_local_player() -> player_t | nilentity.get_players(enemies_only?: boolean) -> table of player_t(1-based list)entity.get_player_resource() -> player_resource_t | nil
ui.find(tab: string, groupbox: string, widget?: string, type?: number) -> ui_element_t | nilui.tab(name: string, icon?: string)ui.groupbox(tab: string, name: string) -> groupbox_t- Widget creation:
gb:checkbox(name, default?)gb:slider_int(name, min, max, default, format?)gb:slider_float(name, min, max, default, format?)gb:combo(name, ...options)gb:multicombo(name, ...options)gb:listbox(name, ...options)gb:listbox_multi(name, ...options)gb:color_picker(name, default?)gb:keybind(name)gb:input(name)gb:button(name)gb:label(name)
ui_element_tmethods:el:get()(Single value) /el:get(index: number)(Multicombo option boolean)el:set(value)/el:set(value, index: number)el:override(value?)/el:override(value?, index?: number)el:set_callback(fn)el:visible(shown: boolean)el:add_gear_item(child_element) -> el(Chainable)el:add_switch(checkbox_element) -> el
render
Section titled “render”render.line(from: vector, to: vector, clr: color)render.rect(from: vector, to: vector, clr: color, rounding?: number)render.rect_outline(from: vector, to: vector, clr: color, rounding?: number)render.gradient(from, to, tl: color, tr: color, bl: color, br: color)render.circle(center: vector, clr: color, radius: number, start_deg?, fraction?)render.circle_outline(center, clr, radius, start_deg?, fraction?, thickness?)render.text(font: number | font_t, pos: vector, clr: color, flags: string, text: string)- Fonts:
1(Verdana),2(Small Fonts),3(Verdana Bold),4(Calibri Bold) - Flags:
"c"(center),"o"(outline),"d"(drop shadow)
- Fonts:
render.measure_text(font, text) -> vector(width, height)render.load_font(name, size, flags?) -> font_trender.load_image(bytes, size?) -> image_t/render.load_svg(svg_markup, size?)render.texture(image: image_t, pos: vector, clr?: color, size?: vector)render.screen_size() -> vector(w, h)render.world_to_screen(world_pos: vector) -> vector(Returns -1, -1 if behind camera)render.project(world_pos: vector) -> vector, boolean(screen_pos, behind_camera)
utils.console_exec(cmd: string)utils.is_key_pressed(vk: number) -> booleanutils.get_mouse_position() -> vectorutils.trace_line(from: vector, to: vector, mask: number, filter?: entity | fn) -> trace_tutils.trace_bullet(attacker: player_t, from: vector, to: vector, target?: player_t) -> fire_bullet_tutils.create_interface(module, name) -> number/utils.pattern_scan(module, pattern) -> number
cvar.<name>orcvar:find(name) -> convar | nilcv:int(val?)/cv:float(val?)/cv:string(val?)(Returns previous value on write)
materials
Section titled “materials”materials.create(name: string, shader: string, keyvalues: table) -> material_tmaterials.find(name: string) -> material_t | nilmaterials.draw_chams(mat: material_t)(Only insidedraw_chamscallback)
rage.get_antiaim_target() -> player_t | nilrage.get_antiaim_yaw() -> numberrage.get_exploit_charge() -> number(0.0..1.0)rage.is_shifting() -> booleanrage.force_charge()/rage.force_teleport()
files, database, json
Section titled “files, database, json”files.read(path) -> string/files.write(path, data) -> boolean/files.exists(path)files.create_folder(path)/files.list(path)/files.delete(path)database.read(key)/database.write(key, val)/database.flush()json.parse(str) -> table/json.stringify(tbl, indent?) -> string
network & http
Section titled “network & http”network.get(url, headers?, callback?)http.get(url, options?, callback?)/http.post(url, options?, callback?)- Callback signature:
function(success: boolean, response: table) - Response table:
response.status,response.body,response.headers,response.timed_out
- Callback signature:
4. Canonical Code Patterns
Section titled “4. Canonical Code Patterns”ESP Visuals Pattern
Section titled “ESP Visuals Pattern”local group = ui.groupbox("Visuals", "Enemy Box")local enabled = group:checkbox("Enabled", true)local box_clr = group:color_picker("Box Color", color(255, 255, 255, 255))
client.add_callback("render", function() if not enabled:get() or not globals.is_in_game then return end
local enemies = entity.get_players(true) for i = 1, #enemies do local enemy = enemies[i] if enemy:is_alive() and not enemy:is_dormant() then local mins, maxs = enemy:get_bounding_box() if mins.x ~= 0 or maxs.x ~= 0 then render.rect_outline(mins, maxs, box_clr:get()) render.text(1, vector(mins.x, mins.y - 14), color(255, 255, 255), "o", enemy:get_name()) end end endend)Movement & UserCmd Pattern
Section titled “Movement & UserCmd Pattern”local IN_JUMP = bit32.lshift(1, 1)
client.add_callback("createmove", function(cmd) local me = entity.get_local_player() if not me or not me:is_alive() then return end
local on_ground = bit32.band(me.m_fFlags, 1) ~= 0 if not on_ground then cmd.buttons = bit32.band(cmd.buttons, bit32.bnot(IN_JUMP)) endend)Anti-Aim Customization Pattern
Section titled “Anti-Aim Customization Pattern”client.add_callback("antiaim", function(ctx) ctx:pitch(89) ctx:yaw_offset(180) ctx:desync(true) ctx:desync_angle(58)end)