Skip to content

ConVars

Each name is looked up once, then cached.

API Description
aqua.cvar.get(name) float, or nil if missing
aqua.cvar.get_int(name) int, or nil
aqua.cvar.get_bool(name) bool, or nil
aqua.cvar.type(name) "bool"/"int32"/"float32"/… , "invalid" if the tag is unavailable, nil if missing
aqua.cvar.exists(name) bool
local vol = aqua.cvar.get("volume") or 1.0
local sens = aqua.cvar.get("sensitivity")
-- Getters CONVERT, so this is fine even though sv_showimpacts is an int cvar:
local impacts = aqua.cvar.get("sv_showimpacts") -- 1.0, not 1.4e-45

The getters convert. A convar’s value is a type-tagged union, and each getter now reads it as its real type and converts - aqua.cvar.get on an int convar returns 1.0, not the float reinterpretation of the bit pattern.

Before 2026-08-06 they reinterpreted raw bytes, so calling the wrong getter returned garbage with nothing to indicate it: sv_showimpacts read back as 1.4012984643248e-45 (the float view of 0x00000001) and looked like a broken or unset convar rather than “enabled”.

One case still behaves the old way: if the type tag fails its runtime validation, conversion is disabled and the getters reinterpret raw bytes again. aqua.cvar.type(name) returns "invalid" in that state, so a script that cares can check for it. It is a fail-closed fallback, not the expected path.