Lifecycle callbacks
on_frame_stage_notify(stage)
Section titled “on_frame_stage_notify(stage)”- Thread: game thread, every frame stage.
- Safe for entity/schema/config/panorama queue/input held state.
aqua.input.key_pressed/mouse_clickedsticky edges are visible for the whole multi-stage burst and cleared after stage12.- Call
aqua.trace_rayhere (or any other non-on_drawgame-thread stage). Cache results in script locals / tables for use inon_draw.
on_draw()
Section titled “on_draw()”- Thread: game thread, once per frame (stage
12,FRAME_RENDER_END), after player data updates, soget_playersand bombs match the built-in ESP for that frame. - Queue overlay draws via
aqua.draw.*. They are drawn together later, so a frame never shows only some of them. - Geometry + text are pixel-snapped together on replay so labels stay locked to rects while moving (bitmap fonts must land on whole pixels).
aqua.trace_rayerrors if called here - do wall/player/smoke casts inon_frame_stage_notifyand draw from the cached result.
on_event(name, data)
Section titled “on_event(name, data)”- Thread: game thread, stage
12, once per frame for everything the engine dispatched since the last frame. nameis the event name ("player_hurt","player_death", …).datais a table of the fields you asked for - seeaqua.events.listenbelow. Fields you did not register are simply absent.- You receive only events your script registered, with only its requested fields. Stopping, errors and unloading remove your subscriptions and queued deliveries.
- Events are snapshotted on the engine’s dispatch thread and replayed here, so this never runs mid-dispatch and cannot stall the game.
aqua.events.listen("player_hurt", { "userid", "attacker", "dmg_health", "hitgroup" })
function on_event(name, data) if name == "player_hurt" then print(("hurt: %d dmg, hitgroup %d"):format(data.dmg_health, data.hitgroup)) endendon_shot(data) / on_shot_hit(data) / on_shot_miss(data)
Section titled “on_shot(data) / on_shot_hit(data) / on_shot_miss(data)”Define these functions to receive copied local-shot notifications on the game thread at stage 12. No explicit event registration is needed; callbacks work with HUD hit/miss logs disabled. Stopping, errors or unloading remove callback interest and queued delivery.
on_shotreports an observed localweapon_fire:time,weapon,command=-1.on_shot_hitreports confirmed local damage:time,weapon,target_handle(full controller handle),target_name,damage,health,hitgroupandreason="confirmed damage". Damage is not assigned an invented command number.on_shot_missreports a ragebot shot with no confirmed damage, as soon as the server’s events for it have arrived (or its RTT window ran out). It includestime,weapon,command,target_handle,target_name,hitchance,reasonandambiguous.reasonis one of"spread","lag compensation","animation mismatch","autowall","shoot position mismatch","prediction error","aim punch","extrapolation","you died","target died","unregistered shot"or"unknown". Unjoined shots carry command/HC -1 and"unknown".
Reasons use the server’s own bullet impacts where the client subscribes to them (non-Valve servers with Rage on); otherwise our client simulation. Overlapping shots, pellets and lost events can remain ambiguous. Manual/script shots have fire/hit callbacks and can produce an unknown no-damage outcome; they do not acquire a ragebot target or hitchance. Callbacks share the bounded event queue and do not write commands.
function on_shot_hit(shot) print(shot.target_name, shot.damage, shot.health)endon_create_move(cmd) / on_create_move_post(cmd)
Section titled “on_create_move(cmd) / on_create_move_post(cmd)”See CreateMove for callback order, command fields, methods and request priorities.
on_unload()
Section titled “on_unload()”- Thread: game thread, once, when the script stops (STOP button, profile change, reload, or shutdown).
- Called before the Lua state is closed, so the script can still touch
aqua.*to release anything it holds. - Optional. A pcall failure here is logged and teardown continues regardless - it cannot wedge a stop.
- Engine-owned resources are released for you afterwards anyway (input lock, music stream); use this for your own bookkeeping, or to stop things early and deliberately.
function on_unload() aqua.sound.stream.stop() print("radio off")endA pcall failure stops the script, sets status to Error (explorer row + console), and prints to the game console + workspace console drawer.