1
0
Fork 0
forked from Simnation/Main
Main/resources/[carscripts]/community_bridge/lib/particles/client/particles.lua
2025-08-06 16:37:06 +02:00

182 lines
No EOL
5.9 KiB
Lua

Particles = {}
Particle = {}
---@diagnostic disable: duplicate-set-field
local Ids = Ids or Require("lib/utility/shared/ids.lua")
local point = Require("lib/points/client/points.lua")
---Loads a ptfx asset into memory.
---@param dict string
---@return boolean
function LoadPtfxAsset(dict)
local failed = 100
while not HasNamedPtfxAssetLoaded(dict) and failed >= 0 do
RequestNamedPtfxAsset(dict)
failed = failed - 1
Wait(100)
end
assert(failed > 0, "Failed to load dict asset: " .. dict)
return HasNamedPtfxAssetLoaded(dict)
end
--- Create a particle effect at the specified position and rotation.
--- @param dict string
--- @param ptfx string
--- @param pos vector3
--- @param rot vector3
--- @param scale number
--- @param color vector3
--- @param looped boolean
--- @param loopLength number|nil
--- @return number|nil ptfxHandle -- The handle of the particle effect, or nil if it failed to create.
function Particle.Play(dict, ptfx, pos, rot, scale, color, looped, loopLength)
LoadPtfxAsset(dict)
UseParticleFxAssetNextCall(dict)
SetParticleFxNonLoopedColour(color.x, color.y, color.z)
local particle = nil
if looped then
particle = StartParticleFxLoopedAtCoord(ptfx, pos.x, pos.y, pos.z, rot.x, rot.y, rot.z, scale, false, false, false, false)
CreateThread(function()
if loopLength then
Wait(loopLength)
Particle.Remove(particle)
end
end)
else
particle = StartParticleFxNonLoopedAtCoord(ptfx, pos.x, pos.y, pos.z, rot.x, rot.y, rot.z, scale, false, false, false, false)
end
return particle
end
function Particle.Stop(particle)
if not particle then return end
StopParticleFxLooped(particle, false)
RemoveParticleFx(particle, false)
RemoveNamedPtfxAsset(particle)
end
function Particle.Create(data)
assert(data, "Particle data is nil")
assert(data.dict, "Invalid particle data. Must contain string dict.")
assert(data.ptfx, "Invalid particle data. Must contain string ptfx.")
local _id = data.id or Ids.CreateUniqueId(Particles)
data = {
id = _id,
dict = data.dict,
ptfx = data.ptfx,
position = data.position or vector3(0.0, 0.0, 0.0),
rotation = data.rotation or vector3(0, 0, 0),
size = data.size or 1.0,
color = data.color or vector3(255, 255, 255),
looped = data.looped or false,
loopLength = data.loopLength or nil,
spawned = false,
}
Particles[_id] = data
point.Register( -- checking if players in range
_id,
data.position,
data.drawDistance or 50.0,
data,
function(_)
if not Particles[_id] then return point.Remove(_id) end
local particleData = Particles[_id]
if particleData.spawned then return end
particleData.spawned = Particle.Play(
particleData.dict,
particleData.ptfx,
particleData.position,
particleData.rotation,
particleData.size,
particleData.color,
particleData.looped,
particleData.loopLength
)
end,
function(markerData)
if not Particles[_id] then return end
local particleData = Particles[_id]
if not particleData.spawned then return end
Particle.Stop(particleData.spawned)
particleData.spawned = nil
end
)
return _id
end
function Particle.Remove(id)
if not id then return end
local particle = Particles[id]
if not particle then return end
Particle.Stop(particle.spawned)
Particles[id] = nil
point.Remove(id)
end
RegisterNetEvent("community_bridge:Client:Particle", function(data)
if not data then return end
Particle.Create(data)
end)
RegisterNetEvent("community_bridge:Client:ParticleBulk", function(datas)
if not datas then return end
for _, data in pairs(datas) do
Particle.Create(data)
end
end)
RegisterNetEvent("community_bridge:Client:ParticleRemove", function(id)
local particle = Particles[id]
if not particle then return end
Particle.Remove(Drawing[id])
end)
RegisterNetEvent("community_bridge:Client:ParticleRemoveBulk", function(ids)
for _, id in pairs(ids) do
Particle.Remove(id)
end
end)
function Particle.CreateOnEntity(dict, ptfx, entity, offset, rot, scale, color, looped, loopLength)
LoadPtfxAsset(dict)
UseParticleFxAssetNextCall(dict)
SetParticleFxNonLoopedColour(color.x, color.y, color.z)
local particle = nil
if looped then
particle = StartNetworkedParticleFxLoopedOnEntity(ptfx, entity, offset.x, offset.y, offset.z, rot.x, rot.y, rot.z, scale, false, false, false)
if loopLength then
Wait(loopLength)
RemoveParticleFxFromEntity(entity)
end
else
particle = StartNetworkedParticleFxLoopedOnEntity(ptfx, entity, offset.x, offset.y, offset.z, rot.x, rot.y, rot.z, scale, false, false, false)
end
RemoveNamedPtfxAsset(ptfx)
return particle
end
function Particle.CreateOnEntityBone(dict, ptfx, entity, bone, offset, rot, scale, color, looped, loopLength)
LoadPtfxAsset(dict)
UseParticleFxAssetNextCall(dict)
SetParticleFxNonLoopedColour(color.x, color.y, color.z)
local particle = nil
if looped then
particle = StartNetworkedParticleFxLoopedOnEntityBone(ptfx, entity, offset.x, offset.y, offset.z, rot.x, rot.y, rot.z, bone, scale, false, false, false)
if loopLength then
Wait(loopLength)
RemoveParticleFxFromEntity(entity)
end
else
particle = StartNetworkedParticleFxNonLoopedOnEntityBone(ptfx, entity, offset.x, offset.y, offset.z, rot.x, rot.y, rot.z, bone, scale, false, false, false)
end
RemoveNamedPtfxAsset(ptfx)
return particle
end
return Particle