Entity Properties
Needs the internal running and needs_internal = true in script_info.
p:get_property("m_FieldName") -> integer | number | boolean | vec3 | nil
row:get("m_FieldName") -> integer | number | boolean | vec3 | nilReads one game field by name, off a player's entity or off a row from entities.by_class. The value comes back with the type the game declares for it.
| Declared type | Lua value |
|---|---|
int8 to int64, uint8 to uint64, GameTick_t, CUtlStringToken, Color | integer |
float32, float64, GameTime_t | number |
bool | boolean |
Vector, QAngle, Vector2D, Vector4D, Quaternion | vec3, the first three components |
CHandle<...>, CEntityHandle, CBaseHandle | integer, the raw handle. Its entity index is handle & 0x7FFF |
Enums, strings, pointers, arrays and structs are not supported and return nil.
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 differ. Which one the health bar shows has not been confirmed.
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; 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)
- 32 pairs are already registered across all scripts
Limits
- 32 (entity, field) pairs across all scripts.
- Values refresh within 250 ms, so poll every few ticks rather than every tick.
- A pair nobody asked for in 10 seconds is dropped.
- Field names up to 47 characters.
- A row is a plain table with a
getmethod and nothing else. Keep callingentities.by_classevery tick; a class nobody asked for in 2 seconds is dropped and you get no rows.
Cheaper external reads that need no flag: p:get_level(), row.health, row.max_health, row.team, and p:get_ability(slot).points for an ability's upgrade tier.
Example
How long each nearby enemy trooper has been alive. my_team, max_m and COL are set earlier in the script:
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
draw.text3d(vec3(e.x, e.y, e.z + 24), string.format("age %.0fs", sim_time() - ct), COL)
end
end
end
endThe player form:
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