Skip to content

Entity Properties ​

Needs the internal running and needs_internal = true in script_info.

p:get_property("m_FieldName" [, rate_ms]) -> integer | number | boolean | vec3 | string | raw_struct | raw_array | nil
row:get("m_FieldName" [, rate_ms])        -> integer | number | boolean | vec3 | string | raw_struct | raw_array | nil

Reads one game field by name from a player's entity or from a row returned by entities.by_class. The value comes back with the type the game declares for it.

Declared typeLua value
int8 to int64, uint8 to uint64, GameTick_t, CUtlStringToken, Colorinteger
float32, float64, GameTime_tnumber
boolboolean
Vector, VectorWS, QAngle, Vector2D, Vector4D, Quaternionvec3, the first three components
CHandle<...>, CEntityHandle, CBaseHandleinteger, the raw handle. Its entity index is handle & 0x7FFF

Enums come back as integers. CUtlString and CUtlSymbolLarge come back as strings, a CUtlVector as a raw_array, and an embedded class or pointer as a raw_struct, the same as Schema Fields.

Fields known to work: m_iHealth, m_iMaxHealth, m_iTeamNum, m_flSimulationTime, m_bTakesDamage, m_vecAbsVelocity, m_hOwnerEntity, m_nLevel, m_lifeState, m_flCreateTime.

p:get_property("m_iMaxHealth") and p:get_max_health() read different fields and can return different values.

Returns nil when ​

  • the internal is not running, or the flag is missing
  • it is the first call for that (entity, field). The first call registers it, and a later call gets the value
  • the class has no such field (logged once)
  • the entity is stale (logged once)
  • the type is unsupported (logged once)
  • 128 pairs are already registered across all scripts

Limits ​

  • 128 (entity, field) pairs across all scripts.
  • Values refresh within 250 ms by default, so poll every few ticks rather than every tick. Pass rate_ms (25 to 2000) as the last argument to refresh one field faster. See Refresh rates.
  • A pair nobody asked for in 10 seconds is dropped.
  • Field names up to 63 characters.
  • Keep calling entities.by_class every tick. A class nobody asked for in 2 seconds is dropped, and then you get no rows.

To read any field the game declares, including strings, lists and nested objects, and to write scalar fields back, see Schema Fields.

Cheaper external reads that need no flag: p:get_level(), row.health, row.max_health, row.team, and p:get_ability_points(slot) for an ability's upgrade tier on any player.

Example ​

How long each nearby enemy trooper has been alive. my_team, max_m and COL are set earlier in the script:

lua
local rows = entities.by_class("npc_trooper")
if rows then
    for _, e in ipairs(rows) do
        if e.team ~= my_team and e.distance_m <= max_m then
            draw.text3d(e.position, string.format("%d/%d  %.0fm", e.health, e.max_health, e.distance_m), COL)
            local ct = e:get("m_flCreateTime")
            if ct then
                -- game.server_time() is "now" on the same clock as m_flCreateTime
                draw.text3d(vec3(e.x, e.y, e.z + 24), string.format("age %.0fs", game.server_time() - ct), COL)
            end
        end
    end
end

The player form:

lua
local me = local_player()
local vel = me and me:get_property("m_vecAbsVelocity")   -- vec3, nil on the first call
if vel then draw.text(40, 300, string.format("%.0f u/s", vel:length()), 0xFFFFFFFF) end