diff --git a/fxmanifest.lua b/fxmanifest.lua index 5ddb371..4fe2e2c 100644 --- a/fxmanifest.lua +++ b/fxmanifest.lua @@ -39,6 +39,8 @@ shared_scripts { client_scripts { 'imports/callback/client.lua', + 'imports/requestModel/client.lua', + 'imports/requestAnimDict/client.lua', 'resource/**/client.lua', 'resource/**/client/*.lua' } diff --git a/imports/requestAnimDict/client.lua b/imports/requestAnimDict/client.lua new file mode 100644 index 0000000..a58f5b4 --- /dev/null +++ b/imports/requestAnimDict/client.lua @@ -0,0 +1,35 @@ +---Load an animation dictionary. When called from a thread, it will yield until it has loaded. +---@param animDict string +---@param timeout number? Number of ticks to wait for the dictionary to load. Default is 500. +---@return string? animDict +function lib.requestAnimDict(animDict, timeout) + if HasAnimDictLoaded(animDict) then return animDict end + + if type(animDict) ~= 'string' then + error(("expected animDict to have type 'string' (received %s)"):format(type(animDict))) + end + + if not DoesAnimDictExist(animDict) then + return error(("attempted to load invalid animDict '%s'"):format(animDict)) + end + + RequestAnimDict(animDict) + + if coroutine.running() then + timeout = tonumber(timeout) or 500 + + for _ = 1, timeout do + if HasAnimDictLoaded(animDict) then + return animDict + end + + Wait(0) + end + + print(("failed to load animDict '%s' after %s ticks"):format(animDict, timeout)) + end + + return animDict +end + +return lib.requestAnimDict diff --git a/imports/requestAnimSet/client.lua b/imports/requestAnimSet/client.lua new file mode 100644 index 0000000..5f54a72 --- /dev/null +++ b/imports/requestAnimSet/client.lua @@ -0,0 +1,31 @@ +---Load an animation clipset. When called from a thread, it will yield until it has loaded. +---@param animSet string +---@param timeout number? Number of ticks to wait for the clipset to load. Default is 500. +---@return string? animSet +function lib.requestAnimSet(animSet, timeout) + if HasAnimSetLoaded(animSet) then return animSet end + + if type(animSet) ~= 'string' then + error(("expected animSet to have type 'string' (received %s)"):format(type(animSet))) + end + + RequestAnimSet(animSet) + + if coroutine.running() then + timeout = tonumber(timeout) or 500 + + for _ = 1, timeout do + if HasAnimSetLoaded(animSet) then + return animSet + end + + Wait(0) + end + + print(("failed to load animSet '%s' after %s ticks"):format(animSet, timeout)) + end + + return animSet +end + +return lib.requestAnimSet diff --git a/imports/requestModel/client.lua b/imports/requestModel/client.lua new file mode 100644 index 0000000..88b5677 --- /dev/null +++ b/imports/requestModel/client.lua @@ -0,0 +1,33 @@ +---Load a model. When called from a thread, it will yield until it has loaded. +---@param model number | string +---@param timeout number? Number of ticks to wait for the model to load. Default is 500. +---@return number? model +function lib.requestModel(model, timeout) + if not tonumber(model) then model = joaat(model) end + ---@cast model -string + if HasModelLoaded(model) then return model end + + if not IsModelValid(model) then + return error(("attempted to load invalid model '%s'"):format(model)) + end + + RequestModel(model) + + if coroutine.running() then + timeout = tonumber(timeout) or 500 + + for _ = 1, timeout do + if HasModelLoaded(model) then + return model + end + + Wait(0) + end + + print(("failed to load model '%s' after %s ticks"):format(model, timeout)) + end + + return model +end + +return lib.requestModel diff --git a/imports/requestNamedPtfxAsset/client.lua b/imports/requestNamedPtfxAsset/client.lua new file mode 100644 index 0000000..0fe9dc1 --- /dev/null +++ b/imports/requestNamedPtfxAsset/client.lua @@ -0,0 +1,31 @@ +---Load a named particle effect. When called from a thread, it will yield until it has loaded. +---@param ptFxName string +---@param timeout number? Number of ticks to wait for the particle effect to load. Default is 500. +---@return string? ptFxName +function lib.requestNamedPtfxAsset(ptFxName, timeout) + if HasNamedPtfxAssetLoaded(ptFxName) then return ptFxName end + + if type(ptFxName) ~= 'string' then + error(("expected ptFxName to have type 'string' (received %s)"):format(type(ptFxName))) + end + + RequestNamedPtfxAsset(ptFxName) + + if coroutine.running() then + timeout = tonumber(timeout) or 500 + + for _ = 1, timeout do + if HasNamedPtfxAssetLoaded(ptFxName) then + return ptFxName + end + + Wait(0) + end + + print(("failed to load ptFxName '%s' after %s ticks"):format(ptFxName, timeout)) + end + + return ptFxName +end + +return lib.requestNamedPtfxAsset diff --git a/imports/requestStreamedTextureDict/client.lua b/imports/requestStreamedTextureDict/client.lua new file mode 100644 index 0000000..66dad57 --- /dev/null +++ b/imports/requestStreamedTextureDict/client.lua @@ -0,0 +1,31 @@ +---Load a texture dictionary. When called from a thread, it will yield until it has loaded. +---@param textureDict string +---@param timeout number? Number of ticks to wait for the dictionary to load. Default is 500. +---@return string? textureDict +function lib.requestStreamedTextureDict(textureDict, timeout) + if HasStreamedTextureDictLoaded(textureDict) then return textureDict end + + if type(textureDict) ~= 'string' then + error(("expected textureDict to have type 'string' (received %s)"):format(type(textureDict))) + end + + RequestStreamedTextureDict(textureDict) + + if coroutine.running() then + timeout = tonumber(timeout) or 500 + + for _ = 1, timeout do + if HasStreamedTextureDictLoaded(textureDict) then + return textureDict + end + + Wait(0) + end + + print(("failed to load textureDict '%s' after %s ticks"):format(textureDict, timeout)) + end + + return textureDict +end + +return lib.requestStreamedTextureDict diff --git a/package/client/resource/streaming/index.ts b/package/client/resource/streaming/index.ts index f1a69b8..41da883 100644 --- a/package/client/resource/streaming/index.ts +++ b/package/client/resource/streaming/index.ts @@ -1,14 +1,47 @@ -export const requestAnimDict = (animDict: string, timeout?: number): string => - exports.ox_lib.requestAnimDict(animDict, timeout); +function streamingRequest( + request: Function, + hasLoaded: Function, + assetType: string, + asset: any, + timeout?: number +): Promise { + return new Promise((resolve, reject) => { + if (hasLoaded(asset)) resolve(asset); -export const requestAnimSet = (animSet: string, timeout?: number): string => - exports.ox_lib.requestAnimSet(animSet, timeout); + request(asset); -export const requestModel = (model: string | number, timeout?: number): string => - exports.ox_lib.requestModel(model, timeout); + if (typeof timeout !== 'number') timeout = 500; -export const requestStreamedTextureDict = (dict: string, timeout?: number): string => - exports.ox_lib.requestStreamedTextureDict(dict, timeout); + let i = 0; -export const requestNamedPtfxAsset = (fxName: string, timeout?: number): string => - exports.ox_lib.requestNamedPtfxAsset(fxName, timeout); + setTick(() => { + if (hasLoaded(asset)) resolve(asset); + + i++; + + if (i === timeout) reject(`failed to load ${assetType} '${asset}' after ${timeout} ticks`); + }); + }); +} + +export const requestAnimDict = (animDict: string, timeout?: number): Promise => { + if (!DoesAnimDictExist(animDict)) throw new Error(`attempted to load invalid animDict '${animDict}'`); + + return streamingRequest(RequestAnimDict, HasAnimDictLoaded, 'animDict', animDict, timeout); +}; + +export const requestAnimSet = (animSet: string, timeout?: number): Promise => + streamingRequest(RequestAnimSet, HasAnimSetLoaded, 'animSet', animSet, timeout); + +export const requestModel = (model: string | number, timeout?: number): Promise => { + if (typeof model !== 'number') model = GetHashKey(model); + if (!IsModelValid(model)) throw new Error(`attempted to load invalid model '${model}'`); + + return streamingRequest(RequestModel, HasModelLoaded, 'model', model, timeout); +}; + +export const requestStreamedTextureDict = (textureDict: string, timeout?: number): Promise => + streamingRequest(RequestStreamedTextureDict, HasStreamedTextureDictLoaded, 'textureDict', textureDict, timeout); + +export const requestNamedPtfxAsset = (ptFxName: string, timeout?: number): Promise => + streamingRequest(RequestNamedPtfxAsset, HasNamedPtfxAssetLoaded, 'ptFxName', ptFxName, timeout); diff --git a/resource/interface/client/progress.lua b/resource/interface/client/progress.lua index 1eddd3f..cd1d787 100644 --- a/resource/interface/client/progress.lua +++ b/resource/interface/client/progress.lua @@ -26,7 +26,10 @@ local function createProp(prop) lib.requestModel(prop.model) local coords = GetEntityCoords(cache.ped) local object = CreateObject(prop.model, coords.x, coords.y, coords.z, true, true, true) + AttachEntityToEntity(object, cache.ped, GetPedBoneIndex(cache.ped, prop.bone or 60309), prop.pos.x, prop.pos.y, prop.pos.z, prop.rot.x, prop.rot.y, prop.rot.z, true, true, false, true, 0, true) + SetModelAsNoLongerNeeded(prop.model) + return object end @@ -44,10 +47,14 @@ local function startProgress(data) if data.anim then if data.anim.dict then lib.requestAnimDict(data.anim.dict) + TaskPlayAnim(cache.ped, data.anim.dict, data.anim.clip, data.anim.blendIn or 3.0, data.anim.blendOut or 1.0, data.anim.duration or -1, data.anim.flag or 49, data.anim.playbackRate or 0, data.anim.lockX, data.anim.lockY, data.anim.lockZ) + RemoveAnimDict(data.anim.dict) + data.anim = true elseif data.anim.scenario then TaskStartScenarioInPlace(cache.ped, data.anim.scenario, 0, data.anim.playEnter ~= nil and data.anim.playEnter or true) + data.anim = true end end diff --git a/resource/streaming/client.lua b/resource/streaming/client.lua deleted file mode 100644 index 876ee15..0000000 --- a/resource/streaming/client.lua +++ /dev/null @@ -1,76 +0,0 @@ -local function request(native, hasLoaded, requestType, name, timeout) - native(name) - - if coroutine.running() then - if not timeout then - timeout = 500 - end - - for i = 1, timeout do - Wait(0) - if hasLoaded(name) then - return name - end - end - - print(("Failed to load %s '%s' after %s ticks"):format(requestType, name, timeout)) - end - - return name -end - ----Load an animation dictionary. When called from a thread, it will yield until it has loaded. ----@param animDict string ----@param timeout number? Number of ticks to wait for the dictionary to load. Default is 500. ----@return string? animDict -function lib.requestAnimDict(animDict, timeout) - if HasAnimDictLoaded(animDict) then return animDict end - - if not DoesAnimDictExist(animDict) then - return error(("Attempted to load invalid animDict (%s)"):format(animDict)) - end - - return request(RequestAnimDict, HasAnimDictLoaded, 'animDict', animDict, timeout) -end - ----Load an animation clipset. When called from a thread, it will yield until it has loaded. ----@param animSet string ----@param timeout number? Number of ticks to wait for the clipset to load. Default is 500. ----@return string? animSet -function lib.requestAnimSet(animSet, timeout) - if HasAnimSetLoaded(animSet) then return animSet end - return request(RequestAnimSet, HasAnimSetLoaded, 'animSet', animSet, timeout) -end - ----Load a model. When called from a thread, it will yield until it has loaded. ----@param model number ----@param timeout number? Number of ticks to wait for the model to load. Default is 500. ----@return number? model -function lib.requestModel(model, timeout) - if not tonumber(model) then model = joaat(model) end - if HasModelLoaded(model) then return model end - - if not IsModelValid(model) then - return error(("Attempted to load invalid model (%s)"):format(model)) - end - - return request(RequestModel, HasModelLoaded, 'model', model, timeout) -end - ----Load a texture dictionary. When called from a thread, it will yield until it has loaded. ----@param textureDict string ----@param timeout number? Number of ticks to wait for the dictionary to load. Default is 500. ----@return string? textureDict -function lib.requestStreamedTextureDict(textureDict, timeout) - if HasStreamedTextureDictLoaded(textureDict) then return textureDict end - return request(RequestStreamedTextureDict, HasStreamedTextureDictLoaded, 'textureDict', textureDict, timeout) -end - ----Load a named particle effect. When called from a thread, it will yield until it has loaded. ----@param fxName string ----@param timeout number? Number of ticks to wait for the particle effect to load. Default is 500. ----@return string? fxName -function lib.requestNamedPtfxAsset(fxName, timeout) - if HasNamedPtfxAssetLoaded(fxName) then return fxName end - return request(RequestNamedPtfxAsset, HasNamedPtfxAssetLoaded, 'fxName', fxName, timeout) -end \ No newline at end of file