Skip to content

EntityInRange ​

The (nearest) entity-in-range interface helps you to easily create event based listeners to check what is the nearest entity to the player.

Example ​

lua
---@type EntityInRangeApi
local EntityInRangeApi = exports.nss_libs:getEntityInRangeApi(GetCurrentResourceName())

-- For more vegetation texture names see https://github.com/OpenIV-Team/RAGE-StringsDatabase/tree/fc6bcdfdda9d79afb4571c35bc4db730b42dc0f4/RDR2/ArchiveItems/hd_0/hd/levels/rdr3/props/vegetation
local tree_texture_names = {
    "p_tree_birch_03",
    "p_tree_birch_03b",
    "p_tree_birch_03_lg",
    "p_tree_birch_03_md",
    "p_tree_birch_03_md_a"
}

---@type EntityInRangeListener
local listener

---@param nearest_entity EntityInRangeData
---@param listener_id number
local on_reach_tree = function(nearest_entity, listener_id)
    print('Reached tree', nearest_entity.entity, listener_id)
end

---@param nearest_entity EntityInRangeData
---@param listener_id number
local on_leave_tree = function(nearest_entity, listener_id)

    print('Left tree', nearest_entity.entity, listener_id)

    -- If declared lister variable is not available you can get listener by given listener_id from event like the
    -- following example:
    local event_listener = EntityInRangeApi.getListenerById(listener_id)

    -- Example for one time only: We remove the listener after tree was left
    event_listener.remove()
end

listener = EntityInRangeApi.create(tree_texture_names, on_reach_tree, on_leave_tree)

Public interface methods ​

.create(texture_names, on_reach_callback, on_leave_callback, custom_range?, custom_height?) ​

Creates a listener that calls the on_reach_callback if the player reaches the nearest entity of given texture_names and vice versa calls the on_leave_callback if the player lefts it.

TIP

The created listener is initially active (on).

Reach is flat, height is separate (since 0.37.7)

custom_range is measured in x/y only, from the player's centre (about a metre above the feet) to the entity origin. The height difference is checked on its own against custom_height. A 3D range of 1.5 m used to leave about 1.1 m of flat reach beside a water pump. Every listener is checked with its own models and its own reach; the monitor ticks every NEAR_TICK_INTERVAL_IN_MS (250 ms) while a matching entity is within reach plus APPROACH_MARGIN_IN_METERS (5 m) of any listener, and every TICK_INTERVAL_IN_MS (1000 ms) otherwise.

ParamTypeDefaultDescription
texture_namestable—Array of texture names
on_reach_callbackfunction—Callback for "on-reach". Receives (nearest_entity, listener_id)
on_leave_callbackfunction?—Callback for "on-left". Same arguments as on_reach_callback
custom_rangenumber?—Flat reach of the listener. Default see Config.EntityInRange.DEFAULT_SEARCH_RADIUS in config.lua
custom_heightnumber?—Allowed height difference. Default see Config.EntityInRange.DEFAULT_HEIGHT_TOLERANCE in config.lua

EntityInRangeData carries distance (3D), flat_distance (x/y) and height_difference (absolute z).

WARNING

Be careful with custom_range, because it can have a big impact on performance.

Returns EntityInRangeListener — the created listener instance


.getListenerById(listener_id) ​

Returns the listener object matching the given listener ID.

ParamTypeDefaultDescription
listener_idnumber—ID of a listener

Returns EntityInRangeListener — the listener object, or nil if not found


.getEntitiesNearby(x, y, z, radius, model_name_or_hash?, entity_type?, filter_func?) ​

Returns the nearest entity (data object EntityInRangeData) of given texture_name or nil if no entity was found.

ParamTypeDefaultDescription
xnumber—X position
ynumber—Y position
znumber—Z position
radiusnumber—Range in meters to search for
model_name_or_hashstring|number|table?—Texture name(s) or hash(es)
entity_typenumber?ENTITY_TYPE_OBJECTEntity type
filter_funcfunction?—Filter function receiving (entity, model_hash), returns boolean

Returns EntityInRangeData[]|nil — array of found entities, or nil

lua
---@type EntityInRangeApi
local EntityInRangeApi = exports.nss_libs:getEntityInRangeApi(GetCurrentResourceName())

local x = 0
local y = 0
local z = 0

-- See https://github.com/femga/rdr3_discoveries/blob/f729ba03f75a591ce5c841642dc873345242f612/peds/peds_list.lua for ped list ...
local texture_names = { "a_c_alligator_01", "a_c_alligator_02" }
local radius = 10.0 -- 10 meters
local entity_type = EntityInRangeApi.ENTITY_TYPE_PLAYER -- Only peds

---@type EntityInRangeApiCustomFilterFunction
local filter_func = function(entity, model_hash)

    -- You can filter what you want, e.g. if the entity is a real player or not, or if it is a animal or not, etc.
    if GetPedType(entity) ~= 4 then
        return false
    end

    return true
end

---@type EntityInRangeData[]|nil
local found_entities = EntityInRangeApi.getEntitiesNearby(x, y, z, radius, texture_names, entity_type, filter_func)

if found_entities then
    print('Found entities: ' .. tostring(json.encode(found_entities)))
else
    print('No entity found')
end

.getNearestObjectEntity(x, y, z, texture_name, range?, entity_type?) ​

Returns the nearest entity (data object EntityInRangeData) of given texture_name or nil if no entity was found.

ParamTypeDefaultDescription
xnumber—X position
ynumber—Y position
znumber—Z position
texture_namestring|number—Texture name or hash
rangenumber?—Range to search for. Default see Config.EntityInRange.DEFAULT_SEARCH_RADIUS in config.lua
entity_typenumber?ENTITY_TYPE_OBJECTEntity type

WARNING

Be careful with the range value, because it can have a big impact on performance.

Returns EntityInRangeData|nil — the nearest entity, or nil

lua
---@type EntityInRangeApi
local EntityInRangeApi = exports.nss_libs:getEntityInRangeApi(GetCurrentResourceName())

local x = 0
local y = 0
local z = 0
local texture_name = "p_tree_birch_03"
local range

---@type EntityInRangeData|nil
local found_entity = EntityInRangeApi.getNearestObjectEntity(x, y, z, texture_name, range)

if found_entity then
    print('Found nearest entity: ' .. tostring(json.encode(found_entity)))
else
    print('No entity found')
end

ENTITY_TYPE_OBJECT ​

Entity type for objects. number, static


ENTITY_TYPE_PLAYER ​

Entity type for players. number, static


ENTITY_TYPE_VEHICLE ​

Entity type for vehicles. number, static


Public methods of EntityInRangeListener ​

.remove() ​

Removes the listener from the main entity-in-range checking loop.

Returns EntityInRangeListener — self


.off() ​

Alias for remove().

Returns EntityInRangeListener — self


.on() ​

Insert the listener back to the main entity-in-range checking loop.

Returns EntityInRangeListener — self


Development notes

Open todos ​

  • [ ] Use cache for static entities in "chunks". The chunk must have a buffer of max range used. Then the cache could re-checked every 10 seconds or so. The cache would reduce the cost of performance.
  • [x] Enable other types as object (e.g. vehicles, peds, etc.) and players as well.
  • [ ] Enable custom delay.

Known issues ​

  • If a related resource is restarted and the player stand inside a range the Entity In Range trys to call the on-leave callback, but the resource is not available anymore. This results in an error.
  • Item sets have a maximum of entities they can handle. All entities above this maximum can not be found. This is a REDM/RDR2 issue.

Performance issues with classes/functions as callback arguments ​

Due to REDM restrictions (due to behavior currently unknown to us) on passing values between exported and non-exported script modules no classes or functions (callbacks) are passed as arguments into events. In this interface only the ID of the listener object is passed instead of the listener object itself. You can then get the listener object via the listener ID if required. This saves a lot of performance.

NIGHTSHIFT STUDIO Documentation