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
---@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.
| Param | Type | Default | Description |
|---|---|---|---|
texture_names | table | — | Array of texture names |
on_reach_callback | function | — | Callback for "on-reach". Receives (nearest_entity, listener_id) |
on_leave_callback | function? | — | Callback for "on-left". Same arguments as on_reach_callback |
custom_range | number? | — | Flat reach of the listener. Default see Config.EntityInRange.DEFAULT_SEARCH_RADIUS in config.lua |
custom_height | number? | — | 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.
| Param | Type | Default | Description |
|---|---|---|---|
listener_id | number | — | 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.
| Param | Type | Default | Description |
|---|---|---|---|
x | number | — | X position |
y | number | — | Y position |
z | number | — | Z position |
radius | number | — | Range in meters to search for |
model_name_or_hash | string|number|table? | — | Texture name(s) or hash(es) |
entity_type | number? | ENTITY_TYPE_OBJECT | Entity type |
filter_func | function? | — | Filter function receiving (entity, model_hash), returns boolean |
Returns EntityInRangeData[]|nil — array of found entities, or nil
---@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.
| Param | Type | Default | Description |
|---|---|---|---|
x | number | — | X position |
y | number | — | Y position |
z | number | — | Z position |
texture_name | string|number | — | Texture name or hash |
range | number? | — | Range to search for. Default see Config.EntityInRange.DEFAULT_SEARCH_RADIUS in config.lua |
entity_type | number? | ENTITY_TYPE_OBJECT | Entity 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
---@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')
endENTITY_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.
