Skip to content

Lifecycle callbacks

  • Thread: game thread, every frame stage.
  • Safe for entity/schema/config/panorama queue/input held state.
  • aqua.input.key_pressed / mouse_clicked sticky edges are visible for the whole multi-stage burst and cleared after stage 12.
  • Call aqua.trace_ray here (or any other non-on_draw game-thread stage). Cache results in script locals / tables for use in on_draw.
  • Thread: game thread, once per frame (stage 12, FRAME_RENDER_END), after player data updates, so get_players and 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_ray errors if called here - do wall/player/smoke casts in on_frame_stage_notify and draw from the cached result.
  • Thread: game thread, stage 12, once per frame for everything the engine dispatched since the last frame.
  • name is the event name ("player_hurt", "player_death", …). data is a table of the fields you asked for - see aqua.events.listen below. 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))
end
end

on_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_shot reports an observed local weapon_fire: time, weapon, command=-1.
  • on_shot_hit reports confirmed local damage: time, weapon, target_handle (full controller handle), target_name, damage, health, hitgroup and reason="confirmed damage". Damage is not assigned an invented command number.
  • on_shot_miss reports 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 includes time, weapon, command, target_handle, target_name, hitchance, reason and ambiguous. reason is 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)
end

on_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.

  • 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")
end

A pcall failure stops the script, sets status to Error (explorer row + console), and prints to the game console + workspace console drawer.