ParticleFxPlayer
Plays particle effects (PTFX) at a world position or attached to an entity. Supports one-shot, looped, infinite, and timed playback. Effects can be rendered locally or over the network.
WARNING
Synced particle fx are restricted by missing natives. For example it is not possible to set the color or alpha of a synced particle fx. If you want that you have to create the particle on each client individually.
Example
Play particle fx on position for one second looped over network
---@type NssLibsParticleFxPlayerControllerApi
local pfx_api = exports.nss_libs:getParticleFxPlayerApi(GetCurrentResourceName())
---@type NssLibsParticleFxPlayerApi
local pfx_player = pfx_api.create()
local duration_in_ms = 1000 -- One second
local interval_in_ms = 100 -- 10 times per second
-- non-looped asset
local asset_dictionary = 'scr_crackpot'
local asset_name = 'scr_crackpot_tesla_fail'
-- false if non-looped asset: https://github.com/femga/rdr3_discoveries/blob/f729ba03f75a591ce5c841642dc873345242f612/graphics/ptfx/ptfx_assets_non_looped.lua
-- true looped asset: https://github.com/femga/rdr3_discoveries/blob/f729ba03f75a591ce5c841642dc873345242f612/graphics/ptfx/ptfx_assets_looped.lua
local is_looped_asset = false
pfx_player
.setAsset(asset_dictionary, asset_name, is_looped_asset)
.setPosition(0.0, 0.0, 0.0)
.useNetwork()
.play(duration_in_ms, interval_in_ms)---@type NssLibsParticleFxPlayerControllerApi
local pfx_api = exports.nss_libs:getParticleFxPlayerApi(GetCurrentResourceName())
---@type NssLibsParticleFxPlayerApi
local pfx_player = pfx_api.create()
local duration_in_ms = 1000 -- One second
-- non-looped asset
local asset_dictionary = 'scr_crackpot'
local asset_name = 'scr_crackpot_tesla_fail'
-- false if non-looped asset: https://github.com/femga/rdr3_discoveries/blob/f729ba03f75a591ce5c841642dc873345242f612/graphics/ptfx/ptfx_assets_non_looped.lua
-- true looped asset: https://github.com/femga/rdr3_discoveries/blob/f729ba03f75a591ce5c841642dc873345242f612/graphics/ptfx/ptfx_assets_looped.lua
local is_looped_asset = false
local random_interval = { 100, 500 } -- Random value between 100 and 500 ms each wait loop
pfx_player
.setAsset(asset_dictionary, asset_name, is_looped_asset)
.setPosition(0.0, 0.0, 0.0)
.useNetwork()
.play(duration_in_ms, random_interval)Commands / Objects
exports.nss_libs:getParticleFxPlayerApi(resource_name)
| Param | Type | Default | Description |
|---|---|---|---|
resource_name | string | — | The name of the resource that uses the ParticleFxPlayer API. Pass GetCurrentResourceName() |
Returns NssLibsParticleFxPlayerControllerApi — object scoped to the calling resource
NssLibsParticleFxPlayerControllerApi
.create()
Creates and registers a new particle fx player instance. The instance is tracked by the controller and can be cleaned up via destroy().
Returns NssLibsParticleFxPlayerApi — the player instance
NssLibsParticleFxPlayerApi
Builder-pattern API. All setter methods return self to allow method chaining. Call play() to start the effect.
.setAsset(pfx_dictionary, pfx_name, is_looped_asset?)
Sets the PTFX asset to use.
| Param | Type | Default | Description |
|---|---|---|---|
pfx_dictionary | string | — | The particle fx dictionary name |
pfx_name | string | — | The particle fx name within the dictionary |
is_looped_asset | boolean? | false | true for looped assets, false for non-looped assets |
Returns self — chainable
.setPosition(x, y, z)
Sets the world position where the effect will be played. Each axis supports an exact value or a random range table {min, max}.
| Param | Type | Default | Description |
|---|---|---|---|
x | number|table | — | World X coordinate, or {min, max} for a random value |
y | number|table | — | World Y coordinate, or {min, max} for a random value |
z | number|table | — | World Z coordinate, or {min, max} for a random value |
Returns self — chainable
.attachToEntity(entity)
Binds the effect to an entity. The effect follows the entity's position. Use setEntityOffset() to define an offset relative to the entity.
| Param | Type | Default | Description |
|---|---|---|---|
entity | number | — | The entity handle to attach to |
Returns self — chainable
.setEntityOffset(x, y, z)
Sets the positional offset relative to the attached entity. Each axis supports an exact value or a random range table {min, max}. Only used when attachToEntity() has been called.
| Param | Type | Default | Description |
|---|---|---|---|
x | number|table | — | X offset, or {min, max} for a random value |
y | number|table | — | Y offset, or {min, max} for a random value |
z | number|table | — | Z offset, or {min, max} for a random value |
Returns self — chainable
.setRotation(rot_x, rot_y, rot_z)
Sets the rotation of the effect in degrees.
| Param | Type | Default | Description |
|---|---|---|---|
rot_x | number | — | Rotation around the X axis |
rot_y | number | — | Rotation around the Y axis |
rot_z | number | — | Rotation around the Z axis |
Returns self — chainable
.setAxis(axis_x, axis_y, axis_z)
Sets the axis values for the effect.
| Param | Type | Default | Description |
|---|---|---|---|
axis_x | number | — | X axis value |
axis_y | number | — | Y axis value |
axis_z | number | — | Z axis value |
Returns self — chainable
.setScale(scale)
Sets the scale of the effect. Supports an exact value or a random range table.
| Param | Type | Default | Description |
|---|---|---|---|
scale | number|table | — | Scale multiplier, or {min, max} for a random value per play cycle |
Returns self — chainable
.setInterval(interval_in_ms)
Sets the interval between repetitions when playing with a duration. Supports an exact value or a random range table.
| Param | Type | Default | Description |
|---|---|---|---|
interval_in_ms | number|table | — | Interval in milliseconds, or {min, max} for a random value per loop iteration |
Returns self — chainable
.useNetwork()
Renders the effect over the network so it is visible to all players. Must be called before play().
Returns self — chainable
.useLocal()
Renders the effect locally only (visible to the local client). This is the default behavior.
Returns self — chainable
.play(duration_in_ms, interval_in_ms?, on_finished?, on_error?)
Starts playback of the effect. Loads the required assets automatically before spawning the effect.
| Param | Type | Default | Description |
|---|---|---|---|
duration_in_ms | number? | — | Total playback duration in ms. -1 for infinite, 0 or nil for one-shot |
interval_in_ms | number|table? | — | Interval between repetitions in ms, or {min, max} for random. Only relevant when duration_in_ms > 0 or -1 |
on_finished | function? | — | Callback invoked when playback ends naturally |
on_error | function? | — | Callback invoked if an error occurs (e.g. asset could not be loaded). Receives (error_msg) |
.stop()
Stops the effect immediately. Does not remove the player instance from the controller.
.destroy()
Stops the effect, removes the PFX handle, and unregisters the player instance from the controller. Use this for full cleanup.
.isPlaying()
Returns boolean — true if the effect is currently active
.isInfinite()
Returns boolean — true if the effect was started with duration_in_ms = -1 (infinite playback)
.getHandle()
Returns number — the internal PFX handle ID assigned by the game engine
.getId()
Returns string — the unique identifier for this player instance
