From b5ea0f7387d62fec30e5d2bf0505577f972a3e22 Mon Sep 17 00:00:00 2001 From: MrNewb <47620135+MrNewb@users.noreply.github.com> Date: Sun, 10 May 2026 14:29:33 -0400 Subject: [PATCH] Add timeouts and validation to asset loaders Enhance several asset-loading helpers in client/functions.lua to avoid indefinite blocking and provide explicit status. LoadModel, RequestAnimDict, LoadAnimSet, and LoadParticleDictionary now accept an optional timeout (default 5000ms), return a boolean load result and the resolved name/hash, and perform existence/validity checks before requesting. LoadModel also accepts string model names (converted via joaat) and logs a warning if the model doesn't exist. These changes make asset loading safer and easier to debug when assets fail to load. Adds timeout as optional param, stops infinite loops on model/animset/anim dict/particle requests No breaking changes and backwards compatable --- client/functions.lua | 55 +++++++++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 13 deletions(-) diff --git a/client/functions.lua b/client/functions.lua index f6bca002d..a14d53ace 100644 --- a/client/functions.lua +++ b/client/functions.lua @@ -356,12 +356,23 @@ end -- Vehicle -function QBCore.Functions.LoadModel(model) - if HasModelLoaded(model) then return end - RequestModel(model) - while not HasModelLoaded(model) do +function QBCore.Functions.LoadModel(model, timeout) + timeout = timeout or 5000 + local modelName = model + if type(modelName) ~= 'number' then modelName = joaat(model) end + if HasModelLoaded(modelName) then return true, model end + + if not IsModelValid(modelName) and not IsModelInCdimage(modelName) then + print(('[QBCore] Model does not exist: %s'):format(modelName or model)) + return false, modelName + end + + RequestModel(modelName) + local count = GetGameTimer() + timeout + while not HasModelLoaded(modelName) and GetGameTimer() < count do Wait(0) end + return HasModelLoaded(modelName), modelName end function QBCore.Functions.SpawnVehicle(model, cb, coords, isnetworked, teleportInto) @@ -880,12 +891,20 @@ function QBCore.Functions.DrawText3D(x, y, z, text) ClearDrawOrigin() end -function QBCore.Functions.RequestAnimDict(animDict) - if HasAnimDictLoaded(animDict) then return end +function QBCore.Functions.RequestAnimDict(animDict, timeout) + timeout = timeout or 5000 + if HasAnimDictLoaded(animDict) then return true, animDict end + if not DoesAnimDictExist(animDict) then + print(('[QBCore] Animation dictionary does not exist: %s'):format(animDict)) + return false, animDict + end + RequestAnimDict(animDict) - while not HasAnimDictLoaded(animDict) do + local count = GetGameTimer() + timeout + while not HasAnimDictLoaded(animDict) and GetGameTimer() < count do Wait(0) end + return HasAnimDictLoaded(animDict), animDict end function QBCore.Functions.GetClosestBone(entity, list) @@ -948,20 +967,30 @@ function QBCore.Functions.SpawnClear(coords, radius) return true end -function QBCore.Functions.LoadAnimSet(animSet) - if HasAnimSetLoaded(animSet) then return end +function QBCore.Functions.LoadAnimSet(animSet, timeout) + timeout = timeout or 5000 + if HasAnimSetLoaded(animSet) then return true, animSet end RequestAnimSet(animSet) - while not HasAnimSetLoaded(animSet) do + + local count = GetGameTimer() + timeout + while not HasAnimSetLoaded(animSet) and GetGameTimer() < count do Wait(0) end + + return HasAnimSetLoaded(animSet), animSet end -function QBCore.Functions.LoadParticleDictionary(dictionary) - if HasNamedPtfxAssetLoaded(dictionary) then return end +function QBCore.Functions.LoadParticleDictionary(dictionary, timeout) + timeout = timeout or 5000 + if HasNamedPtfxAssetLoaded(dictionary) then return true, dictionary end RequestNamedPtfxAsset(dictionary) - while not HasNamedPtfxAssetLoaded(dictionary) do + + local count = GetGameTimer() + timeout + while not HasNamedPtfxAssetLoaded(dictionary) and GetGameTimer() < count do Wait(0) end + + return HasNamedPtfxAssetLoaded(dictionary), dictionary end function QBCore.Functions.StartParticleAtCoord(dict, ptName, looped, coords, rot, scale, alpha, color, duration)