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

155 lines
No EOL
5.3 KiB
Lua

Anim = Anim or {}
Ids = Ids or Require("lib/utility/shared/ids.lua")
Anim.Active = Anim.Active or {}
Anim.isUpdateLoopRunning = Anim.isUpdateLoopRunning or false
--- This will request the animation dictionary.
--- @param animDict string
--- @return boolean
function Anim.RequestDict(animDict)
if not animDict or type(animDict) ~= "string" then
return false
end
if HasAnimDictLoaded(animDict) then
return true
end
RequestAnimDict(animDict)
local timeout = GetGameTimer() + 2000
while not HasAnimDictLoaded(animDict) and GetGameTimer() < timeout do
Wait(50)
end
return HasAnimDictLoaded(animDict)
end
--- This will start the animation update loop.
function Anim.Start()
if Anim.isUpdateLoopRunning then return end
Anim.isUpdateLoopRunning = true
CreateThread(function()
while Anim.isUpdateLoopRunning do
local idsToProcess = {}
for idKey, _ in pairs(Anim.Active) do
table.insert(idsToProcess, idKey)
end
if #idsToProcess == 0 then
Wait(750)
else
for _, id in ipairs(idsToProcess) do
local animData = Anim.Active[id]
if animData then
local entity = animData.entity
local onComplete = animData.onComplete
if not DoesEntityExist(entity) then
if onComplete then onComplete(false, "despawned") end
Anim.Active[id] = nil
elseif animData.status == "pending_task" then
TaskPlayAnim(entity, animData.animDict, animData.animName, animData.blendIn, animData.blendOut, animData.duration, animData.flag, animData.playbackRate, false, false, false)
animData.startTime = GetGameTimer()
animData.animEndTime = animData.duration > 0 and (animData.startTime + animData.duration) or -1
animData.status = "playing"
elseif animData.status == "playing" then
local animationCompletedNaturally = false
if animData.duration == -1 then
if not IsEntityPlayingAnim(entity, animData.animDict, animData.animName, 3) and GetEntityAnimCurrentTime(entity, animData.animDict, animData.animName) > 0.8 then
animationCompletedNaturally = true
end
elseif animData.animEndTime ~= -1 and GetGameTimer() >= animData.animEndTime then
animationCompletedNaturally = true
end
if animationCompletedNaturally then
if onComplete then onComplete(true, "completed") end
Anim.Active[id] = nil
end
end
end
end
Wait(100)
end
end
end)
end
--- This will play an animation on the specified ped.
--- @param id string | nil
--- @param entity number
--- @param animDict string
--- @param animName string
--- @param blendIn number | nil
--- @param blendOut number | nil
--- @param duration number | nil
--- @param flag number | nil
--- @param playbackRate number | nil
--- @param onComplete function | nil
--- @return string | nil
function Anim.Play(id, entity, animDict, animName, blendIn, blendOut, duration, flag, playbackRate, onComplete)
local newId = id or Ids.CreateUniqueId(Anim.Active)
if Anim.Active[newId] then
if onComplete then
onComplete(false, "id_in_use")
end
return newId
end
if not entity or not DoesEntityExist(entity) or not IsEntityAPed(entity) then
if onComplete then
onComplete(false, "invalid_entity")
end
return nil
end
if not Anim.RequestDict(animDict) then
if onComplete then
onComplete(false, "dict_load_failed")
end
return nil
end
Anim.Active[newId] = {
entity = entity,
animDict = animDict,
animName = animName,
blendIn = blendIn or 8.0,
blendOut = blendOut or -8.0,
duration = duration or -1,
flag = flag or 1,
playbackRate = playbackRate or 0.0,
onComplete = onComplete,
status = "pending_task",
startTime = 0,
animEndTime = 0
}
Anim.Start()
return newId
end
function Anim.Stop(id)
if not id or not Anim.Active or not Anim.Active[id] then
return false
end
local animData = Anim.Active[id]
if animData.entity and DoesEntityExist(animData.entity) and IsEntityAPed(animData.entity) then
if animData.status == "playing" or animData.status == "pending_task" then
StopAnimTask(animData.entity, animData.animDict, animData.animName, 1.0)
end
end
if animData.onComplete then
animData.onComplete(false, "stopped_by_id")
end
Anim.Active[id] = nil
local anyLeft = Anim.Active and next(Anim.Active) ~= nil
if not anyLeft then
Anim.isUpdateLoopRunning = false
end
return true
end
return Anim