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.
This commit is contained in:
Linden
2024-03-31 16:15:44 +11:00
parent e3ece4f337
commit 0f0c7a6591
10 changed files with 50 additions and 74 deletions

View File

@@ -1,7 +1,7 @@
---Load an animation dictionary. When called from a thread, it will yield until it has loaded. ---Load an animation dictionary. When called from a thread, it will yield until it has loaded.
---@param animDict string ---@param animDict string
---@param timeout number? Approximate milliseconds to wait for the dictionary to load. Default is 1000. ---@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) function lib.requestAnimDict(animDict, timeout)
if HasAnimDictLoaded(animDict) then return animDict end if HasAnimDictLoaded(animDict) then return animDict end
@@ -10,16 +10,10 @@ function lib.requestAnimDict(animDict, timeout)
end end
if not DoesAnimDictExist(animDict) then 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 end
RequestAnimDict(animDict) return lib.streamingRequest(RequestAnimDict, HasAnimDictLoaded, 'animDict', animDict, timeout)
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)
end end
return lib.requestAnimDict return lib.requestAnimDict

View File

@@ -1,7 +1,7 @@
---Load an animation clipset. When called from a thread, it will yield until it has loaded. ---Load an animation clipset. When called from a thread, it will yield until it has loaded.
---@param animSet string ---@param animSet string
---@param timeout number? Approximate milliseconds to wait for the clipset to load. Default is 1000. ---@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) function lib.requestAnimSet(animSet, timeout)
if HasAnimSetLoaded(animSet) then return animSet end 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))) error(("expected animSet to have type 'string' (received %s)"):format(type(animSet)))
end end
RequestAnimSet(animSet) return lib.streamingRequest(RequestAnimSet, HasAnimSetLoaded, 'animSet', animSet, timeout)
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)
end end
return lib.requestAnimSet return lib.requestAnimSet

View File

@@ -1,23 +1,16 @@
---Load a model. When called from a thread, it will yield until it has loaded. ---Load a model. When called from a thread, it will yield until it has loaded.
---@param model number | string ---@param model number | string
---@param timeout number? Approximate milliseconds to wait for the model to load. Default is 1000. ---@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) function lib.requestModel(model, timeout)
if not tonumber(model) then model = joaat(model) end if type(model) ~= 'number' then model = joaat(model) end
---@cast model -string
if HasModelLoaded(model) then return model end if HasModelLoaded(model) then return model end
if not IsModelValid(model) then 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 end
RequestModel(model) return lib.streamingRequest(RequestModel, HasModelLoaded, 'model', model, timeout)
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)
end end
return lib.requestModel return lib.requestModel

View File

@@ -1,7 +1,7 @@
---Load a named particle effect. When called from a thread, it will yield until it has loaded. ---Load a named particle effect. When called from a thread, it will yield until it has loaded.
---@param ptFxName string ---@param ptFxName string
---@param timeout number? Approximate milliseconds to wait for the particle effect to load. Default is 1000. ---@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) function lib.requestNamedPtfxAsset(ptFxName, timeout)
if HasNamedPtfxAssetLoaded(ptFxName) then return ptFxName end 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))) error(("expected ptFxName to have type 'string' (received %s)"):format(type(ptFxName)))
end end
RequestNamedPtfxAsset(ptFxName) return lib.streamingRequest(RequestNamedPtfxAsset, HasNamedPtfxAssetLoaded, 'ptFxName', ptFxName, timeout)
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)
end end
return lib.requestNamedPtfxAsset return lib.requestNamedPtfxAsset

View File

@@ -1,19 +1,13 @@
---Load a scaleform movie. When called from a thread, it will yield until it has loaded. ---Load a scaleform movie. When called from a thread, it will yield until it has loaded.
---@param scaleformName string ---@param scaleformName string
---@param timeout number? Approximate milliseconds to wait for the scaleform movie to load. Default is 1000. ---@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) function lib.requestScaleformMovie(scaleformName, timeout)
if type(scaleformName) ~= 'string' then if type(scaleformName) ~= 'string' then
error(("expected scaleformName to have type 'string' (received %s)"):format(type(scaleformName))) error(("expected scaleformName to have type 'string' (received %s)"):format(type(scaleformName)))
end end
local scaleform = RequestScaleformMovie(scaleformName) return lib.streamingRequest(RequestScaleformMovie, HasScaleformMovieLoaded, 'scaleformMovie', scaleformName, timeout)
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)
end end
return lib.requestScaleformMovie return lib.requestScaleformMovie

View File

@@ -1,7 +1,7 @@
---Load a texture dictionary. When called from a thread, it will yield until it has loaded. ---Load a texture dictionary. When called from a thread, it will yield until it has loaded.
---@param textureDict string ---@param textureDict string
---@param timeout number? Approximate milliseconds to wait for the dictionary to load. Default is 1000. ---@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) function lib.requestStreamedTextureDict(textureDict, timeout)
if HasStreamedTextureDictLoaded(textureDict) then return textureDict end 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))) error(("expected textureDict to have type 'string' (received %s)"):format(type(textureDict)))
end end
RequestStreamedTextureDict(textureDict, false) return lib.streamingRequest(RequestStreamedTextureDict, HasStreamedTextureDictLoaded, 'textureDict', textureDict, timeout)
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)
end end
return lib.requestStreamedTextureDict return lib.requestStreamedTextureDict

View File

@@ -20,7 +20,7 @@
---@param timeout number? Approximate milliseconds to wait for the asset to load. Default is 1000. ---@param timeout number? Approximate milliseconds to wait for the asset to load. Default is 1000.
---@param weaponResourceFlags WeaponResourceFlags? Default is 31. ---@param weaponResourceFlags WeaponResourceFlags? Default is 31.
---@param extraWeaponComponentFlags ExtraWeaponComponentFlags? Default is 0. ---@param extraWeaponComponentFlags ExtraWeaponComponentFlags? Default is 0.
---@return string | number? weaponType ---@return string | number weaponType
function lib.requestWeaponAsset(weaponType, timeout, weaponResourceFlags, extraWeaponComponentFlags) function lib.requestWeaponAsset(weaponType, timeout, weaponResourceFlags, extraWeaponComponentFlags)
if HasWeaponAssetLoaded(weaponType) then return weaponType end 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))) error(("expected extraWeaponComponentFlags to have type 'number' (received %s)"):format(type(extraWeaponComponentFlags)))
end end
RequestWeaponAsset(weaponType, weaponResourceFlags or 31, extraWeaponComponentFlags or 0) return lib.streamingRequest(RequestWeaponAsset, HasWeaponAssetLoaded, 'weaponHash', weaponType, timeout, 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)
end end
return lib.requestWeaponAsset return lib.requestWeaponAsset

View File

@@ -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

View File

@@ -1,6 +1,6 @@
---Yields the current thread until a non-nil value is returned by the function. ---Yields the current thread until a non-nil value is returned by the function.
---@generic T ---@generic T
---@param cb fun(): T ---@param cb fun(): T?
---@param errMessage string? ---@param errMessage string?
---@param timeout? number | false Error out after `~x` ms. Defaults to 1000, unless set to `false`. ---@param timeout? number | false Error out after `~x` ms. Defaults to 1000, unless set to `false`.
---@return T ---@return T

View File

@@ -1,13 +1,13 @@
import { waitFor } from '../../'; import { waitFor } from '../../';
function streamingRequest( function streamingRequest<T extends string | number>(
request: Function, request: Function,
hasLoaded: Function, hasLoaded: Function,
assetType: string, assetType: string,
asset: any, asset: T,
timeout?: number, timeout: number = 1000,
...args: any ...args: any
): Promise<any> { ) {
if (hasLoaded(asset)) return asset; if (hasLoaded(asset)) return asset;
request(asset, ...args); request(asset, ...args);
@@ -16,34 +16,34 @@ function streamingRequest(
() => { () => {
if (hasLoaded(asset)) return asset; if (hasLoaded(asset)) return asset;
}, },
`failed to load ${assetType} '${asset}' after ${timeout} ticks`, `failed to load ${assetType} '${asset}'`,
timeout || 500 timeout
); );
} }
export const requestAnimDict = (animDict: string, timeout?: number): Promise<string> => { export const requestAnimDict = (animDict: string, timeout?: number) => {
if (!DoesAnimDictExist(animDict)) throw new Error(`attempted to load invalid animDict '${animDict}'`); if (!DoesAnimDictExist(animDict)) throw new Error(`attempted to load invalid animDict '${animDict}'`);
return streamingRequest(RequestAnimDict, HasAnimDictLoaded, 'animDict', animDict, timeout); return streamingRequest(RequestAnimDict, HasAnimDictLoaded, 'animDict', animDict, timeout);
}; };
export const requestAnimSet = (animSet: string, timeout?: number): Promise<string> => export const requestAnimSet = (animSet: string, timeout?: number) =>
streamingRequest(RequestAnimSet, HasAnimSetLoaded, 'animSet', animSet, timeout); streamingRequest(RequestAnimSet, HasAnimSetLoaded, 'animSet', animSet, timeout);
export const requestModel = (model: string | number, timeout?: number): Promise<number> => { export const requestModel = (model: string | number, timeout?: number) => {
if (typeof model !== 'number') model = GetHashKey(model); if (typeof model !== 'number') model = GetHashKey(model);
if (!IsModelValid(model)) throw new Error(`attempted to load invalid model '${model}'`); if (!IsModelValid(model)) throw new Error(`attempted to load invalid model '${model}'`);
return streamingRequest(RequestModel, HasModelLoaded, 'model', model, timeout); return streamingRequest(RequestModel, HasModelLoaded, 'model', model, timeout);
}; };
export const requestNamedPtfxAsset = (ptFxName: string, timeout?: number): Promise<string> => export const requestNamedPtfxAsset = (ptFxName: string, timeout?: number) =>
streamingRequest(RequestNamedPtfxAsset, HasNamedPtfxAssetLoaded, 'ptFxName', ptFxName, timeout); streamingRequest(RequestNamedPtfxAsset, HasNamedPtfxAssetLoaded, 'ptFxName', ptFxName, timeout);
export const requestScaleformMovie = (scaleformName: string, timeout?: number): Promise<string> => export const requestScaleformMovie = (scaleformName: string, timeout?: number) =>
streamingRequest(RequestScaleformMovie, HasScaleformMovieLoaded, 'scaleformMovie', scaleformName, timeout); streamingRequest(RequestScaleformMovie, HasScaleformMovieLoaded, 'scaleformMovie', scaleformName, timeout);
export const requestStreamedTextureDict = (textureDict: string, timeout?: number): Promise<string> => export const requestStreamedTextureDict = (textureDict: string, timeout?: number) =>
streamingRequest(RequestStreamedTextureDict, HasStreamedTextureDictLoaded, 'textureDict', textureDict, timeout); streamingRequest(RequestStreamedTextureDict, HasStreamedTextureDictLoaded, 'textureDict', textureDict, timeout);
export const requestWeaponAsset = ( export const requestWeaponAsset = (
@@ -51,7 +51,7 @@ export const requestWeaponAsset = (
timeout?: number, timeout?: number,
weaponResourceFlags: number = 31, weaponResourceFlags: number = 31,
extraWeaponComponentFlags: number = 0 extraWeaponComponentFlags: number = 0
): Promise<string | number> => ) =>
streamingRequest( streamingRequest(
RequestWeaponAsset, RequestWeaponAsset,
HasWeaponAssetLoaded, HasWeaponAssetLoaded,