From 0f0c7a659124659b038dd2e0be9f004b76c7ce10 Mon Sep 17 00:00:00 2001 From: Linden <65407488+thelindat@users.noreply.github.com> Date: Sun, 31 Mar 2024 16:15:44 +1100 Subject: [PATCH] refactor(streamingRequest): internal method for request functions - TS package type inference for request functions. - Type fix for Lua's waitFor callback. - Lua request functions cannot return nil. --- imports/requestAnimDict/client.lua | 12 +++------ imports/requestAnimSet/client.lua | 10 ++----- imports/requestModel/client.lua | 15 +++-------- imports/requestNamedPtfxAsset/client.lua | 10 ++----- imports/requestScaleformMovie/client.lua | 10 ++----- imports/requestStreamedTextureDict/client.lua | 10 ++----- imports/requestWeaponAsset/client.lua | 10 ++----- imports/streamingRequest/client.lua | 19 ++++++++++++++ imports/waitFor/shared.lua | 2 +- package/client/resource/streaming/index.ts | 26 +++++++++---------- 10 files changed, 50 insertions(+), 74 deletions(-) create mode 100644 imports/streamingRequest/client.lua diff --git a/imports/requestAnimDict/client.lua b/imports/requestAnimDict/client.lua index 2e57c6f..622e488 100644 --- a/imports/requestAnimDict/client.lua +++ b/imports/requestAnimDict/client.lua @@ -1,7 +1,7 @@ ---Load an animation dictionary. When called from a thread, it will yield until it has loaded. ---@param animDict string ---@param timeout number? Approximate milliseconds to wait for the dictionary to load. Default is 1000. ----@return string? animDict +---@return string animDict function lib.requestAnimDict(animDict, timeout) if HasAnimDictLoaded(animDict) then return animDict end @@ -10,16 +10,10 @@ function lib.requestAnimDict(animDict, timeout) end if not DoesAnimDictExist(animDict) then - return error(("attempted to load invalid animDict '%s'"):format(animDict)) + error(("attempted to load invalid animDict '%s'"):format(animDict)) end - RequestAnimDict(animDict) - - if not coroutine.isyieldable() then return animDict end - - return lib.waitFor(function() - if HasAnimDictLoaded(animDict) then return animDict end - end, ("failed to load animDict '%s'"):format(animDict), timeout) + return lib.streamingRequest(RequestAnimDict, HasAnimDictLoaded, 'animDict', animDict, timeout) end return lib.requestAnimDict diff --git a/imports/requestAnimSet/client.lua b/imports/requestAnimSet/client.lua index bd523ac..11d4b1c 100644 --- a/imports/requestAnimSet/client.lua +++ b/imports/requestAnimSet/client.lua @@ -1,7 +1,7 @@ ---Load an animation clipset. When called from a thread, it will yield until it has loaded. ---@param animSet string ---@param timeout number? Approximate milliseconds to wait for the clipset to load. Default is 1000. ----@return string? animSet +---@return string animSet function lib.requestAnimSet(animSet, timeout) if HasAnimSetLoaded(animSet) then return animSet end @@ -9,13 +9,7 @@ function lib.requestAnimSet(animSet, timeout) error(("expected animSet to have type 'string' (received %s)"):format(type(animSet))) end - RequestAnimSet(animSet) - - if not coroutine.isyieldable() then return animSet end - - return lib.waitFor(function() - if HasAnimSetLoaded(animSet) then return animSet end - end, ("failed to load animSet '%s'"):format(animSet), timeout) + return lib.streamingRequest(RequestAnimSet, HasAnimSetLoaded, 'animSet', animSet, timeout) end return lib.requestAnimSet diff --git a/imports/requestModel/client.lua b/imports/requestModel/client.lua index a36bbb7..4994bea 100644 --- a/imports/requestModel/client.lua +++ b/imports/requestModel/client.lua @@ -1,23 +1,16 @@ ---Load a model. When called from a thread, it will yield until it has loaded. ---@param model number | string ---@param timeout number? Approximate milliseconds to wait for the model to load. Default is 1000. ----@return number? model +---@return number model function lib.requestModel(model, timeout) - if not tonumber(model) then model = joaat(model) end - ---@cast model -string + if type(model) ~= 'number' 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)) + error(("attempted to load invalid model '%s'"):format(model)) end - RequestModel(model) - - if not coroutine.isyieldable() then return model end - - return lib.waitFor(function() - if HasModelLoaded(model) then return model end - end, ("failed to load model '%s'"):format(model), timeout) + return lib.streamingRequest(RequestModel, HasModelLoaded, 'model', model, timeout) end return lib.requestModel diff --git a/imports/requestNamedPtfxAsset/client.lua b/imports/requestNamedPtfxAsset/client.lua index a1b2498..450433e 100644 --- a/imports/requestNamedPtfxAsset/client.lua +++ b/imports/requestNamedPtfxAsset/client.lua @@ -1,7 +1,7 @@ ---Load a named particle effect. When called from a thread, it will yield until it has loaded. ---@param ptFxName string ---@param timeout number? Approximate milliseconds to wait for the particle effect to load. Default is 1000. ----@return string? ptFxName +---@return string ptFxName function lib.requestNamedPtfxAsset(ptFxName, timeout) if HasNamedPtfxAssetLoaded(ptFxName) then return ptFxName end @@ -9,13 +9,7 @@ function lib.requestNamedPtfxAsset(ptFxName, timeout) error(("expected ptFxName to have type 'string' (received %s)"):format(type(ptFxName))) end - RequestNamedPtfxAsset(ptFxName) - - if not coroutine.isyieldable() then return ptFxName end - - return lib.waitFor(function() - if HasNamedPtfxAssetLoaded(ptFxName) then return ptFxName end - end, ("failed to load ptFxName '%s'"):format(ptFxName), timeout) + return lib.streamingRequest(RequestNamedPtfxAsset, HasNamedPtfxAssetLoaded, 'ptFxName', ptFxName, timeout) end return lib.requestNamedPtfxAsset diff --git a/imports/requestScaleformMovie/client.lua b/imports/requestScaleformMovie/client.lua index 6a15a29..5b8026f 100644 --- a/imports/requestScaleformMovie/client.lua +++ b/imports/requestScaleformMovie/client.lua @@ -1,19 +1,13 @@ ---Load a scaleform movie. When called from a thread, it will yield until it has loaded. ---@param scaleformName string ---@param timeout number? Approximate milliseconds to wait for the scaleform movie to load. Default is 1000. ----@return number? scaleform +---@return number scaleform function lib.requestScaleformMovie(scaleformName, timeout) if type(scaleformName) ~= 'string' then error(("expected scaleformName to have type 'string' (received %s)"):format(type(scaleformName))) end - local scaleform = RequestScaleformMovie(scaleformName) - - if not coroutine.isyieldable() then return scaleform end - - return lib.waitFor(function() - if HasScaleformMovieLoaded(scaleform) then return scaleform end - end, ("failed to load scaleform '%s'"):format(scaleform), timeout) + return lib.streamingRequest(RequestScaleformMovie, HasScaleformMovieLoaded, 'scaleformMovie', scaleformName, timeout) end return lib.requestScaleformMovie diff --git a/imports/requestStreamedTextureDict/client.lua b/imports/requestStreamedTextureDict/client.lua index 225aefd..64cfd44 100644 --- a/imports/requestStreamedTextureDict/client.lua +++ b/imports/requestStreamedTextureDict/client.lua @@ -1,7 +1,7 @@ ---Load a texture dictionary. When called from a thread, it will yield until it has loaded. ---@param textureDict string ---@param timeout number? Approximate milliseconds to wait for the dictionary to load. Default is 1000. ----@return string? textureDict +---@return string textureDict function lib.requestStreamedTextureDict(textureDict, timeout) if HasStreamedTextureDictLoaded(textureDict) then return textureDict end @@ -9,13 +9,7 @@ function lib.requestStreamedTextureDict(textureDict, timeout) error(("expected textureDict to have type 'string' (received %s)"):format(type(textureDict))) end - RequestStreamedTextureDict(textureDict, false) - - if not coroutine.isyieldable() then return textureDict end - - return lib.waitFor(function() - if HasStreamedTextureDictLoaded(textureDict) then return textureDict end - end, ("failed to load textureDict '%s'"):format(textureDict), timeout) + return lib.streamingRequest(RequestStreamedTextureDict, HasStreamedTextureDictLoaded, 'textureDict', textureDict, timeout) end return lib.requestStreamedTextureDict diff --git a/imports/requestWeaponAsset/client.lua b/imports/requestWeaponAsset/client.lua index d727edb..349df8c 100644 --- a/imports/requestWeaponAsset/client.lua +++ b/imports/requestWeaponAsset/client.lua @@ -20,7 +20,7 @@ ---@param timeout number? Approximate milliseconds to wait for the asset to load. Default is 1000. ---@param weaponResourceFlags WeaponResourceFlags? Default is 31. ---@param extraWeaponComponentFlags ExtraWeaponComponentFlags? Default is 0. ----@return string | number? weaponType +---@return string | number weaponType function lib.requestWeaponAsset(weaponType, timeout, weaponResourceFlags, extraWeaponComponentFlags) if HasWeaponAssetLoaded(weaponType) then return weaponType end @@ -38,13 +38,7 @@ function lib.requestWeaponAsset(weaponType, timeout, weaponResourceFlags, extraW error(("expected extraWeaponComponentFlags to have type 'number' (received %s)"):format(type(extraWeaponComponentFlags))) end - RequestWeaponAsset(weaponType, weaponResourceFlags or 31, extraWeaponComponentFlags or 0) - - if not coroutine.isyieldable() then return weaponType end - - return lib.waitFor(function() - if HasWeaponAssetLoaded(weaponType) then return weaponType end - end, ("failed to load weaponType '%s'"):format(weaponType), timeout) + return lib.streamingRequest(RequestWeaponAsset, HasWeaponAssetLoaded, 'weaponHash', weaponType, timeout, weaponResourceFlags or 31, extraWeaponComponentFlags or 0) end return lib.requestWeaponAsset diff --git a/imports/streamingRequest/client.lua b/imports/streamingRequest/client.lua new file mode 100644 index 0000000..70796a5 --- /dev/null +++ b/imports/streamingRequest/client.lua @@ -0,0 +1,19 @@ +---@async +---@package +---@generic T : string | number +---@param request function +---@param hasLoaded function +---@param assetType string +---@param asset T +---@param timeout? number +---@param ... any +---Used internally. +function lib.streamingRequest(request, hasLoaded, assetType, asset, timeout, ...) + if hasLoaded(asset) then return asset end + + request(asset, ...) + + return lib.waitFor(function() + if hasLoaded(asset) then return asset end + end, ("failed to load %s '%s'"):format(assetType), timeout) +end diff --git a/imports/waitFor/shared.lua b/imports/waitFor/shared.lua index 2492adc..2470562 100644 --- a/imports/waitFor/shared.lua +++ b/imports/waitFor/shared.lua @@ -1,6 +1,6 @@ ---Yields the current thread until a non-nil value is returned by the function. ---@generic T ----@param cb fun(): T +---@param cb fun(): T? ---@param errMessage string? ---@param timeout? number | false Error out after `~x` ms. Defaults to 1000, unless set to `false`. ---@return T diff --git a/package/client/resource/streaming/index.ts b/package/client/resource/streaming/index.ts index b569674..1e68f22 100644 --- a/package/client/resource/streaming/index.ts +++ b/package/client/resource/streaming/index.ts @@ -1,13 +1,13 @@ import { waitFor } from '../../'; -function streamingRequest( +function streamingRequest( request: Function, hasLoaded: Function, assetType: string, - asset: any, - timeout?: number, + asset: T, + timeout: number = 1000, ...args: any -): Promise { +) { if (hasLoaded(asset)) return asset; request(asset, ...args); @@ -16,34 +16,34 @@ function streamingRequest( () => { if (hasLoaded(asset)) return asset; }, - `failed to load ${assetType} '${asset}' after ${timeout} ticks`, - timeout || 500 + `failed to load ${assetType} '${asset}'`, + timeout ); } -export const requestAnimDict = (animDict: string, timeout?: number): Promise => { +export const requestAnimDict = (animDict: string, timeout?: number) => { 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 => +export const requestAnimSet = (animSet: string, timeout?: number) => streamingRequest(RequestAnimSet, HasAnimSetLoaded, 'animSet', animSet, timeout); -export const requestModel = (model: string | number, timeout?: number): Promise => { +export const requestModel = (model: string | number, timeout?: number) => { 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 requestNamedPtfxAsset = (ptFxName: string, timeout?: number): Promise => +export const requestNamedPtfxAsset = (ptFxName: string, timeout?: number) => streamingRequest(RequestNamedPtfxAsset, HasNamedPtfxAssetLoaded, 'ptFxName', ptFxName, timeout); -export const requestScaleformMovie = (scaleformName: string, timeout?: number): Promise => +export const requestScaleformMovie = (scaleformName: string, timeout?: number) => streamingRequest(RequestScaleformMovie, HasScaleformMovieLoaded, 'scaleformMovie', scaleformName, timeout); -export const requestStreamedTextureDict = (textureDict: string, timeout?: number): Promise => +export const requestStreamedTextureDict = (textureDict: string, timeout?: number) => streamingRequest(RequestStreamedTextureDict, HasStreamedTextureDictLoaded, 'textureDict', textureDict, timeout); export const requestWeaponAsset = ( @@ -51,7 +51,7 @@ export const requestWeaponAsset = ( timeout?: number, weaponResourceFlags: number = 31, extraWeaponComponentFlags: number = 0 -): Promise => +) => streamingRequest( RequestWeaponAsset, HasWeaponAssetLoaded,