HOOZiDocs
Skip to content

game

Live data (read-only, writes raise a Lua error). Accessing a field = the latest published snapshot for the current frame.


game.localplayer

FieldTypeDescription
indexintentity_list index
base / self_baseuint64Entity memory base — combine with offsets + mem.read/write to self-service read/write any attribute. The two diverge while dead-spectating: base follows the spectated player, self_base is always the real local machine — use self_base to read "my own" attributes
health / max_healthintCurrent / max HP
shield / max_shieldintCurrent / max shield
origin / camera_originVec3Entity / camera position (origin follows the spectated player while dead)
view_angleVec2{pitch, yaw}
sway_angleVec2Bullet firing direction including breath/sway
view_offset / punch_angleVec3View offset / recoil
abs_velocityVec3
flags_rawuint32Raw m_fFlags bits (FL_ONGROUND etc.)
team_num / squad_idint
platform_uidstringuint64 → string
weapon_idintWeapon string-table index
weapon_enumintsdk::ItemId value, more reliable than the weapon string
weaponstringWeapon name shown in ESP
weapon_speed / weapon_scalenumberFire rate / charge-up
target_zoom_fovnumberADS fov of the current weapon
weapon_next_ready_timenumber
weap_state / burst_fire_index / ammo_in_clipintInternal ammo state
is_semi_auto / is_zooming / is_dead / is_down / is_skydive / is_grenade / is_hands / is_on_groundbool
time_basenumberWorld time base
spec_indexintSpectated target
backpack_tierint0=None / 1=White / 2=Blue / 3=Purple / 4=Gold
consumablestable16-slot consumable inventory (each slot {item: uint16, count: uint16}; count==0 = empty)

game.entities.players (iterable via pairs)

Per-PlayerEntity fields:

FieldTypeDescription
indexintentity_list index
baseuint64Entity memory base — combine with offsets + mem.read/write for self-service reads
name / weapon / legend / legend_icon_keystring
platform_uidstringuint64 → string
rosteruint8Roster bitmask (pro/celeb/cheater/friends)
grade / kills / damage / xpintLevel / kills / damage / experience
rank / rank_icon_key / rank_colorstringRank info
rank_sourceintRaw rank score
distancenumberMeters
origin / head_pos / abs_velocityVec3
vec_min / vec_maxVec3Collision AABB
yawnumberYaw angle
team_num / squad_idint
health / shield / max_shieldint
flagsintm_fFlags state bits
weapon_idintWeapon string-table index
spec_indexintWhom this player is spectating
last_visible_time / cloak_endtimenumberVisibility / cloak timestamps
is_visible / is_down / is_dead / is_teammate / is_cloak / is_npcbool
in_screen / can_draw / has_bones / is_model_blocked / is_glow / is_wallboolRendering-related state

#game.entities.players does not work (userdata-backed tables have no #) — count with for _ in pairs(...) do n = n + 1 end.

Skeleton

PlayerEntity exposes 17 bone world positions; pair with game.BONE (part constants) and game.BONE_LINKS (connection table) to draw skeleton ESP.

Member / constantDescription
player:bone(idx)World-space Vec3 of body part idx (0-based body part id); returns a zero vector if out of range or bones not ready
player:has_fresh_bones()Whether all 17 bones were actually read this frame (when false, bone() is likely zero — skip)
game.BONENamed part constants: head=0, upper_chest, chest, waist, hip, l_shoulder, l_elbow, l_hand, r_shoulder, r_elbow, r_hand, l_thigh, l_knee, l_foot, r_thigh, r_knee, r_foot=16
game.BONE_LINKSArray of {a, b} part-id pairs (matches the native skeleton, 16 segments)

math.WorldToScreen(world) returns 3 values (sx, sy, ok), not a Vec2.

lua
-- Skeleton ESP: iterate links, project each bone to screen, draw a line
local LINKS = game.BONE_LINKS
event.on("frame_update", function()
    for _, p in pairs(game.entities.players) do
        if p.is_visible and not p.is_dead and not p.is_teammate and p:has_fresh_bones() then
            for _, link in ipairs(LINKS) do
                local ax, ay, ok1 = math.WorldToScreen(p:bone(link[1]))
                local bx, by, ok2 = math.WorldToScreen(p:bone(link[2]))
                if ok1 and ok2 then
                    draw.line(ax, ay, bx, by, draw.u8(255, 255, 255, 200), 1.5)
                end
            end
        end
    end
end)

game.entities.loots (iterable via pairs)

Per-LootEntity fields:

FieldTypeDescription
indexintentity_list index
baseuint64Entity memory base — combine with offsets + mem.read/write for self-service reads
originVec3
distancenumberMeters
model_namestring
model_hashuint32hash of model_name
classified_idintItemId enum value
classified_name / item_id_str / base_namestringClassified names
quality_levelint0=unknown, 1..5=COMMON..HEIRLOOM
weapon_name_indexintWeapon string-table index
custom_script_intint
context_idint

game.entities.projectiles (iterable via pairs)

Per-ProjectileEntity fields:

FieldTypeDescription
indexintentity_list index
baseuint64Entity memory base — combine with offsets + mem.read/write for self-service reads
kindstring"frag" / "thermite" / "arc_star" / "other" / "unknown"
originVec3
team_numint
dmg_radiusnumberm_DmgRadius (0x2f94)
owner_handle_rawuint32Raw EHandle bits of m_hOwnerEntity
weapon_class_indexuint16m_weaponClassIndex; pair with game.world to look up weapon name
creation_timenumberEntity birth time (ctx.time at once_read)
is_throwableboolReal player grenade (filters static map props)
is_enemy / is_localbool

game.aimbot (read-only)

FieldTypeDescription
target_indexintEntity index of the current aimbot target (-1 when no target)
target_distancenumber (meters)Distance to the current target
predict_posVec3 | nilThe aimbot's internal predicted target position
trigger_busyboolWhether the trigger decision is currently in a busy state (for custom trigger HUDs)
triggertableDetailed trigger state snapshot (see below, for trigger HUDs)

weapon_next_ready_time is on game.localplayer; trigger state is not its own namespace to avoid duplicate paths.

game.aimbot.trigger

All timestamps are engine-clock seconds (QPC, base::get_time), not time.game()/time.now(). The table includes a same-clock now; use it for countdowns (e.g. ready_in = t.weapon_ready_at - t.now).

FieldTypeDescription
nownumberCurrent engine clock (QPC seconds), same clock as the timestamps below; use it for countdowns
busyboolIn a hold/release-window countdown
target_indexintTarget being evaluated (0 = none)
pressedboolAlready mouse_down
last_hitboolWhether the last evaluation hit
snapshot_timenumberGame time of this snapshot
release_at / again_atnumberPlanned mouse_up / next-allowed-fire time
visible_atnumberTarget visible start (react timing origin)
weapon_ready_atnumberWeapon ready time (incl. rdyfudge)
react_window / again_window / release_windownumberReact / re-fire / hold-duration windows
rdyfudge / radscalenumberReady offset / radius scale
aim_offsetVec3Offset of the aim part relative to spine_head
lua
event.on("frame_update", function()
    local t = game.aimbot.trigger
    if t.target_index ~= 0 then
        local ready_in = math.max(0, t.weapon_ready_at - t.now)
        draw.text(20, 200, draw.u8(255,255,255,255),
                  string.format("trigger: tgt=%d hit=%s ready_in=%.2f",
                                t.target_index, tostring(t.last_hit), ready_in))
    end
end)

Custom aim algorithms (movement/smoothing + prediction override)

Scripts can register their own movement algorithm (added to the dropdown) and prediction algorithm (global override). Execution model: callbacks run on the render thread (same thread as the Lua VM — no lock). Smoothing cadence = min(aim publish rate, render FPS) (uncapped render → high rate); prediction is slow-changing, so the render thread computes the aim point and the aim thread consumes it at 500Hz with no cadence loss. The native Normal/PID paths are unaffected.

game.aimbot.solve(shooter, target_pos, target_vel, v0, gravity){pitch, yaw, time} | nil

Native ballistic solver (stateless, callable anywhere). pitch/yaw are Source angles (degrees, pitch +down), time is flight time (seconds). v0 ≤ 1 is treated as hitscan (time=0); out of range returns nil. Coordinates are world-space Vec3, velocity u/s, gravity u/s².

game.aimbot.register_algorithm(name, fn)

Register a movement algorithm. name is appended to the aim / trigger Movement Algorithm dropdown; when selected, this algorithm drives mouse smoothing. fn(state) returns dx, dy (mickey delta; the engine accumulates sub-pixel residue). Auto-unregistered on script unload.

Must be called from the script's top-level load body — deferred callbacks (event.on("frame_update", ...), Delay(), gui.Button callbacks, etc.) are rejected with a throttled log warning, because the owner identity is cleared after load completion and cannot be reliably attributed (would silently leak across scripts). For lazy enable, keep register_algorithm in the body and gate behavior with a Lua-side flag.

state fields:

fieldtypemeaning
err_pitch / err_yawnumber (deg)current aim error (prediction-compensated + dead-zoned)
dtnumber (s)time since this algorithm was last called
distancenumber (m)target distance
zoomingboolADS or not
mouse_sensnumberin-game sensitivity (for screen-consistent scaling: err/0.022/mouse_sens → mickey)
target_indexinttarget entity index
shooter / swayVec3 / Vec2shooter origin / current reference view
target / velocityVec3world hit point / target velocity (u/s)

Sign convention matches native: dx = -err_yaw·k, dy = err_pitch·k.

game.aimbot.set_predictor(fn)

Globally override the prediction algorithm. fn(target) returns a world aim point Vec3; the aim thread consumes it at 500Hz in place of native solve. Pass nil to clear (fall back to native). target fields: index, shooter, head, origin, velocity (Vec3), distance, v0, gravity.

Same as register_algorithmload-body-only. Also one-predictor-per-process: if another script already owns the predictor, calls are rejected silently to Lua (throttled log only). Convention: one predictor per process, or unload the holding script first.

lua
local tab  = gui.tab("AimAlgo")
local g    = tab:group("g", "Lua Aim Algo", 0, 0, 300, 0)
local gain = g:slider_float("gain", "Strength (mickey/deg)", 0.55, 0.05, 2.0)
local lead = g:checkbox("lead", "Prediction override", true)

-- Adaptive easing smoother: appears in the dropdown, active when selected
game.aimbot.register_algorithm("Lua Adaptive", function(s)
    local mag = math.sqrt(s.err_pitch^2 + s.err_yaw^2)
    local f   = gain:get() * (1.0 - 0.4 * math.exp(-mag))   -- soft near target, full far
    return -s.err_yaw * f, s.err_pitch * f
end)

-- Prediction override: reuse native solve for flight time, extrapolate by velocity
game.aimbot.set_predictor(function(t)
    if not lead:get() then return t.head end
    local sol = game.aimbot.solve(t.shooter, t.head, t.velocity, t.v0, t.gravity)
    if not sol then return t.head end
    return Vec3(t.head.x + t.velocity.x * sol.time,
                t.head.y + t.velocity.y * sol.time,
                t.head.z + t.velocity.z * sol.time)
end)

game.world

FieldTypeDescription
ringtable{origin=Vec3, radius_start=N, radius_end=N, time_start=N, time_end=N, is_active=bool}; radius / origin are in game units (≈ inches), divide by 39.37 for meters
map_namestringCurrent map string

game top-level methods

MethodReturnsDescription
game:is_in_game()boolWhether currently in a match (signon_state + not in lobby/match-making)
game:signon_state()intRaw client_state.signon_state

Example

lua
local lp = game.localplayer
if lp.is_dead then return end

for _, p in pairs(game.entities.players) do
    if (not p.is_teammate) and p.is_visible and p.distance < 50 then
        log.info("Enemy " .. (p.name or "?") .. " at " .. p.distance .. "m")
    end
end

if game.world.map_name == "mp_rr_arena_skygarden" then
    -- ...
end