2025-03-18 18:46:09 +11:00
--[[
https : // github.com / overextended / ox_lib
This file is licensed under LGPL - 3.0 or higher < https : // www.gnu . org / licenses / lgpl - 3.0 . en.html >
Copyright ( c ) 2025 Linden < https : // github.com / thelindat / fivem >
] ]
2024-05-03 15:49:33 +10:00
local pendingCallbacks = { }
local cbEvent = ' __ox_cb_%s '
2024-05-21 05:50:06 +10:00
local callbackTimeout = GetConvarInt ( ' ox:callbackTimeout ' , 300000 )
2022-02-28 16:30:58 +11:00
2022-06-19 13:08:28 +10:00
RegisterNetEvent ( cbEvent : format ( cache.resource ) , function ( key , ... )
2024-05-22 16:36:22 +10:00
local cb = pendingCallbacks [ key ]
2025-02-03 15:41:58 +11:00
if not cb then return end
2024-05-03 15:49:33 +10:00
pendingCallbacks [ key ] = nil
2025-02-03 15:41:58 +11:00
cb ( ... )
2022-06-09 05:15:27 +10:00
end )
---@param _ any
---@param event string
---@param playerId number
2022-08-08 17:16:57 +10:00
---@param cb function|false
---@param ... any
2023-02-06 13:22:19 +11:00
---@return ...
2022-06-09 05:15:27 +10:00
local function triggerClientCallback ( _ , event , playerId , cb , ... )
2024-05-22 16:36:22 +10:00
assert ( DoesPlayerExist ( playerId --[[@as string]] ) , ( " target playerId '%s' does not exist " ) : format ( playerId ) )
2022-06-09 05:15:27 +10:00
2024-05-22 16:36:22 +10:00
local key
2022-06-09 05:15:27 +10:00
2024-05-22 16:36:22 +10:00
repeat
key = ( ' %s:%s:%s ' ) : format ( event , math.random ( 0 , 100000 ) , playerId )
until not pendingCallbacks [ key ]
2022-06-09 05:15:27 +10:00
2025-02-03 15:41:58 +11:00
TriggerClientEvent ( ' ox_lib:validateCallback ' , playerId , event , cache.resource , key )
2024-05-22 16:36:22 +10:00
TriggerClientEvent ( cbEvent : format ( event ) , playerId , cache.resource , key , ... )
2022-06-09 05:15:27 +10:00
2024-05-22 16:36:22 +10:00
---@type promise | false
local promise = not cb and promise.new ( )
pendingCallbacks [ key ] = function ( response , ... )
2025-02-03 15:41:58 +11:00
if response == ' cb_invalid ' then
response = ( " callback '%s' does not exist " ) : format ( event )
return promise and promise : reject ( response ) or error ( response )
end
2022-12-11 12:39:40 +11:00
response = { response , ... }
2022-06-09 05:15:27 +10:00
2024-05-22 16:36:22 +10:00
if promise then
return promise : resolve ( response )
end
2022-06-09 05:15:27 +10:00
2022-12-11 12:39:40 +11:00
if cb then
cb ( table.unpack ( response ) )
2022-10-25 03:02:44 +11:00
end
2024-05-22 16:36:22 +10:00
end
2022-06-09 05:15:27 +10:00
2024-05-22 16:36:22 +10:00
if promise then
2024-05-03 15:49:33 +10:00
SetTimeout ( callbackTimeout , function ( ) promise : reject ( ( " callback event '%s' timed out " ) : format ( key ) ) end )
2024-05-22 16:36:22 +10:00
return table.unpack ( Citizen.Await ( promise ) )
end
2022-06-09 05:15:27 +10:00
end
---@overload fun(event: string, playerId: number, cb: function, ...)
2022-09-14 00:50:27 +10:00
lib.callback = setmetatable ( { } , {
2024-05-22 16:36:22 +10:00
__call = function ( _ , event , playerId , cb , ... )
2024-05-23 09:41:24 +10:00
if not cb then
warn ( ( " callback event '%s' does not have a function to callback to and will instead await \n use lib.callback.await or a regular event to remove this warning " )
: format ( event ) )
else
local cbType = type ( cb )
2024-05-22 16:36:22 +10:00
2025-01-20 02:10:02 +11:00
if cbType == ' table ' and getmetatable ( cb ) ? . __call then
cbType = ' function '
end
2024-05-23 09:41:24 +10:00
assert ( cbType == ' function ' , ( " expected argument 3 to have type 'function' (received %s) " ) : format ( cbType ) )
end
2024-05-22 16:36:22 +10:00
return triggerClientCallback ( _ , event , playerId , cb , ... )
end
2022-06-09 05:15:27 +10:00
} )
---@param event string
---@param playerId number
--- Sends an event to a client and halts the current thread until a response is returned.
2024-05-22 16:36:22 +10:00
---@diagnostic disable-next-line: duplicate-set-field
2022-09-14 00:50:27 +10:00
function lib . callback . await ( event , playerId , ... )
2024-05-22 16:36:22 +10:00
return triggerClientCallback ( nil , event , playerId , false , ... )
2022-06-09 05:15:27 +10:00
end
2022-08-25 18:49:07 +10:00
local function callbackResponse ( success , result , ... )
2024-05-22 16:36:22 +10:00
if not success then
if result then
return print ( ( ' ^1SCRIPT ERROR: %s^0 \n %s ' ) : format ( result ,
Citizen.InvokeNative ( ` FORMAT_STACK_TRACE ` & 0xFFFFFFFF , nil , 0 , Citizen.ResultAsString ( ) ) or ' ' ) )
end
2022-08-25 18:49:07 +10:00
2024-05-22 16:36:22 +10:00
return false
end
2022-08-25 18:49:07 +10:00
2024-05-22 16:36:22 +10:00
return result , ...
2022-08-25 18:49:07 +10:00
end
local pcall = pcall
2022-02-28 16:30:58 +11:00
---@param name string
2022-03-10 14:23:25 +00:00
---@param cb function
2024-05-22 16:36:22 +10:00
---Registers an event handler and callback function to respond to client requests.
---@diagnostic disable-next-line: duplicate-set-field
2022-09-14 00:50:27 +10:00
function lib . callback . register ( name , cb )
2025-02-03 15:41:58 +11:00
event = cbEvent : format ( name )
lib.setValidCallback ( name , true )
RegisterNetEvent ( event , function ( resource , key , ... )
2024-05-22 16:36:22 +10:00
TriggerClientEvent ( cbEvent : format ( resource ) , source , key , callbackResponse ( pcall ( cb , source , ... ) ) )
end )
2022-02-28 16:30:58 +11:00
end
2022-10-19 20:20:38 +11:00
return lib.callback