refractor callbacks
This commit is contained in:
1 parent
a015e681b3
commit
aa1e621f90
1 file changed
+127
-187
+127
-187
@@ -1,197 +1,137 @@
|
|||||||
Callbacks = {}
|
local Callback = {}
|
||||||
cbData = {}
|
local CallbackRegistry = {}
|
||||||
Callback = Callback or {}
|
|
||||||
|
|
||||||
--=======================================
|
-- Constants
|
||||||
-- ▀█▀ █▄█ █ █▄ █ █▄▀ ▄▀▄ ██▄ ▄▀▄ █ █ ▀█▀ ▄▀▄ █▀▄ █▀▄ █ █▄ █ ▄▀ █▀▄ █▀▄ ▄▀▄ █▄ ▄█ █ ▄▀▀ ██▀ ▄▀▀ ▀█▀ ▄▀▄ ▄▀▀ ▄▀▄ █ █ ██▄ ▄▀▄ ▄▀▀ █▄▀ ▄▀▀
|
local RESOURCE = GetCurrentResourceName() or 'unknown'
|
||||||
-- █ █ █ █ █ ▀█ █ █ █▀█ █▄█ ▀▄▀ ▀▄█ █ █▀█ █▄▀ █▄▀ █ █ ▀█ ▀▄█ █▀ █▀▄ ▀▄▀ █ ▀ █ █ ▄█▀ █▄▄ ▄█▀ █ ▀▄▀ ▀▄▄ █▀█ █▄▄ █▄▄ █▄█ █▀█ ▀▄▄ █ █ ▄█▀
|
local EVENT_NAMES = {
|
||||||
--=======================================
|
CLIENT_TO_SERVER = RESOURCE .. ':CS:Callback',
|
||||||
|
SERVER_TO_CLIENT = RESOURCE .. ':SC:Callback',
|
||||||
|
CLIENT_RESPONSE = RESOURCE .. ':CSR:Callback',
|
||||||
|
SERVER_RESPONSE = RESOURCE .. ':SCR:Callback'
|
||||||
|
}
|
||||||
|
|
||||||
local resource = GetCurrentResourceName() or 'unknown'
|
-- Utility functions
|
||||||
|
local function generateCallbackId(name)
|
||||||
|
return string.format('%s_%d', name, math.random(1000000, 9999999))
|
||||||
|
end
|
||||||
|
|
||||||
local clientToServerName = resource .. ':server:CS:TriggerCallback'
|
local function handleResponse(registry, name, callbackId, ...)
|
||||||
local clientToServerBackToClientName = resource .. ':client:CSC:TriggerCallback'
|
local data = registry[callbackId]
|
||||||
|
if not data then return end
|
||||||
|
|
||||||
local serverToClientName = resource .. ':client:SC:TriggerCallback'
|
if data.callback then
|
||||||
local serverToClientBackToServerName = resource .. ':server:SCS:TriggerCallback'
|
data.callback(...)
|
||||||
|
end
|
||||||
|
|
||||||
|
if data.promise then
|
||||||
|
data.promise:resolve({ ... })
|
||||||
|
end
|
||||||
|
|
||||||
|
registry[callbackId] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local function triggerCallback(eventName, target, name, args, callback)
|
||||||
|
local callbackId = generateCallbackId(name)
|
||||||
|
local promise = promise.new()
|
||||||
|
|
||||||
|
CallbackRegistry[callbackId] = {
|
||||||
|
callback = callback,
|
||||||
|
promise = promise
|
||||||
|
}
|
||||||
|
|
||||||
|
if type(target) == 'table' then
|
||||||
|
for _, id in ipairs(target) do
|
||||||
|
TriggerClientEvent(eventName, tonumber(id), name, callbackId, table.unpack(args))
|
||||||
|
end
|
||||||
|
else
|
||||||
|
TriggerClientEvent(eventName, tonumber(target), name, callbackId, table.unpack(args))
|
||||||
|
end
|
||||||
|
|
||||||
|
if not callback then
|
||||||
|
local result = Citizen.Await(promise)
|
||||||
|
return #result == 1 and result[1] or table.unpack(result)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Server-side implementation
|
||||||
|
if IsDuplicityVersion() then
|
||||||
|
function Callback.Register(name, handler)
|
||||||
|
Callback[name] = handler
|
||||||
|
end
|
||||||
|
|
||||||
|
function Callback.Trigger(name, target, ...)
|
||||||
|
local args = { ... }
|
||||||
|
local callback = type(args[1]) == 'function' and table.remove(args, 1) or nil
|
||||||
|
return triggerCallback(EVENT_NAMES.SERVER_TO_CLIENT, target or -1, name, args, callback)
|
||||||
|
end
|
||||||
|
|
||||||
|
RegisterNetEvent(EVENT_NAMES.CLIENT_TO_SERVER, function(name, callbackId, ...)
|
||||||
|
local handler = Callback[name]
|
||||||
|
if not handler then return end
|
||||||
|
|
||||||
|
local result = table.pack(handler(source, ...))
|
||||||
|
TriggerClientEvent(EVENT_NAMES.CLIENT_RESPONSE, source, name, callbackId, table.unpack(result))
|
||||||
|
end)
|
||||||
|
|
||||||
|
RegisterNetEvent(EVENT_NAMES.SERVER_RESPONSE, function(name, callbackId, ...)
|
||||||
|
handleResponse(CallbackRegistry, name, callbackId, ...)
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- Client-side implementation
|
||||||
|
else
|
||||||
|
local ClientCallbacks = {}
|
||||||
|
local ReboundCallbacks = {}
|
||||||
|
|
||||||
|
function Callback.Register(name, handler)
|
||||||
|
ClientCallbacks[name] = handler
|
||||||
|
end
|
||||||
|
|
||||||
|
function Callback.RegisterRebound(name, handler)
|
||||||
|
ReboundCallbacks[name] = handler
|
||||||
|
end
|
||||||
|
|
||||||
|
function Callback.Trigger(name, ...)
|
||||||
|
local args = { ... }
|
||||||
|
local callback = type(args[1]) == 'function' and table.remove(args, 1) or nil
|
||||||
|
|
||||||
|
local callbackId = generateCallbackId(name)
|
||||||
|
local promise = promise.new()
|
||||||
|
|
||||||
|
CallbackRegistry[callbackId] = {
|
||||||
|
callback = callback,
|
||||||
|
promise = promise
|
||||||
|
}
|
||||||
|
|
||||||
|
TriggerServerEvent(EVENT_NAMES.CLIENT_TO_SERVER, name, callbackId, table.unpack(args))
|
||||||
|
|
||||||
|
if not callback then
|
||||||
|
local result = Citizen.Await(promise)
|
||||||
|
return #result == 1 and result[1] or table.unpack(result)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
RegisterNetEvent(EVENT_NAMES.CLIENT_RESPONSE, function(name, callbackId, ...)
|
||||||
|
if ReboundCallbacks[name] then
|
||||||
|
ReboundCallbacks[name](...)
|
||||||
|
end
|
||||||
|
handleResponse(CallbackRegistry, name, callbackId, ...)
|
||||||
|
end)
|
||||||
|
|
||||||
|
RegisterNetEvent(EVENT_NAMES.SERVER_TO_CLIENT, function(name, callbackId, ...)
|
||||||
|
local handler = ClientCallbacks[name]
|
||||||
|
if not handler then return end
|
||||||
|
|
||||||
|
local result = table.pack(handler(...))
|
||||||
|
TriggerServerEvent(EVENT_NAMES.SERVER_RESPONSE, name, callbackId, table.unpack(result))
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Exports
|
||||||
exports('Callback', Callback)
|
exports('Callback', Callback)
|
||||||
|
|
||||||
if not IsDuplicityVersion() then goto client end
|
|
||||||
|
|
||||||
-- -- -- -- -- -- -- -- -- --
|
|
||||||
-- ▄▀▀ ██▀ █▀▄ █ █ ██▀ █▀▄
|
|
||||||
-- ▄█▀ █▄▄ █▀▄ ▀▄▀ █▄▄ █▀▄
|
|
||||||
-- -- -- -- -- -- -- -- -- --
|
|
||||||
|
|
||||||
-- client to server rebound
|
|
||||||
function Callback.Register(name, callback, all)
|
|
||||||
Callback[name] = {
|
|
||||||
callback = callback,
|
|
||||||
toAll = all
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Handle client requests and send response back to client(s)
|
|
||||||
RegisterNetEvent(clientToServerName, function(name, cbId, ...)
|
|
||||||
local src = source
|
|
||||||
local data = Callback[name]
|
|
||||||
if not data then return end
|
|
||||||
local func = data.callback
|
|
||||||
if not func then return end
|
|
||||||
local toAll = data.toAll and -1 or src
|
|
||||||
|
|
||||||
-- Create response handler
|
|
||||||
local packed = table.pack(func(src, ...))
|
|
||||||
TriggerClientEvent(clientToServerBackToClientName, toAll, name, cbId, table.unpack(packed))
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- Server to client trigger function - supports both callback and direct return
|
|
||||||
function Callback.Trigger(name, src, callbackOrArg, ...)
|
|
||||||
if src == nil then src = -1 end
|
|
||||||
|
|
||||||
-- Determine if the third parameter is a callback function or an argument
|
|
||||||
local hasCallback = type(callbackOrArg) == 'function' or (type(callbackOrArg) == 'table' and rawget(callbackOrArg, '__cfx_functionReference'))
|
|
||||||
local callback = hasCallback and callbackOrArg or nil
|
|
||||||
-- Adjust args based on whether the callback is present
|
|
||||||
local args = hasCallback and {...} or {callbackOrArg, ...}
|
|
||||||
|
|
||||||
local cbId = name .. '_' .. math.random(1000000, 9999999)
|
|
||||||
local p = promise.new()
|
|
||||||
|
|
||||||
-- Store promise data
|
|
||||||
cbData[cbId] = {
|
|
||||||
cb = callback,
|
|
||||||
p = p
|
|
||||||
}
|
|
||||||
|
|
||||||
-- Trigger for single player or multiple players
|
|
||||||
if type(src) == 'table' then
|
|
||||||
for i, d in pairs(src) do
|
|
||||||
TriggerClientEvent(serverToClientName, tonumber(d), name, cbId, table.unpack(args))
|
|
||||||
end
|
|
||||||
else
|
|
||||||
TriggerClientEvent(serverToClientName, tonumber(src), name, cbId, table.unpack(args))
|
|
||||||
end
|
|
||||||
|
|
||||||
-- If no callback was provided, wait for the promise and return directly
|
|
||||||
|
|
||||||
local result = Citizen.Await(p)
|
|
||||||
-- If there's only one value, return it directly
|
|
||||||
if #result == 1 then
|
|
||||||
return result[1]
|
|
||||||
else
|
|
||||||
return table.unpack(result or {})
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Handle responses to server requests
|
|
||||||
RegisterNetEvent(serverToClientBackToServerName, function(name, cbId, ...)
|
|
||||||
local data = cbData[cbId]
|
|
||||||
if not data then return end
|
|
||||||
|
|
||||||
-- Process callback if provided
|
|
||||||
|
|
||||||
if data.cb then
|
|
||||||
data.cb({...})
|
|
||||||
end
|
|
||||||
-- Always resolve the promise with all args for direct returns
|
|
||||||
data.p:resolve({...})
|
|
||||||
cbData[cbId] = nil
|
|
||||||
end)
|
|
||||||
|
|
||||||
exports('RegisterCallback', Callback.Register)
|
exports('RegisterCallback', Callback.Register)
|
||||||
exports('TriggerCallback', Callback.Trigger)
|
exports('TriggerCallback', Callback.Trigger)
|
||||||
|
if not IsDuplicityVersion() then
|
||||||
-- -- -- -- -- -- -- -- -- --
|
exports('RegisterRebound', Callback.RegisterRebound)
|
||||||
-- ▄▀▀ █ █ ██▀ █▄ █ ▀█▀
|
|
||||||
-- ▀▄▄ █▄▄ █ █▄▄ █ ▀█ █
|
|
||||||
-- -- -- -- -- -- -- -- -- --
|
|
||||||
if IsDuplicityVersion() then return Callback end
|
|
||||||
::client::
|
|
||||||
|
|
||||||
cbRebounds = {}
|
|
||||||
function Callback.Register(name, callback)
|
|
||||||
Callback[name] = {
|
|
||||||
callback = callback,
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function Callback.RegisterRebound(name, callback)
|
return Callback
|
||||||
cbRebounds[name] = callback
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Client to server trigger - supports both callback and direct return
|
|
||||||
function Callback.Trigger(name, callbackOrArg, ...)
|
|
||||||
-- Determine if the second parameter is a callback function or an argument
|
|
||||||
local hasCallback = type(callbackOrArg) == 'function' or (type(callbackOrArg) == 'table' and rawget(callbackOrArg, '__cfx_functionReference'))
|
|
||||||
local callback = hasCallback and callbackOrArg or nil
|
|
||||||
-- Adjust args based on whether the callback is present
|
|
||||||
local args = hasCallback and {...} or {callbackOrArg, ...}
|
|
||||||
|
|
||||||
local cbId = name .. '_' .. math.random(1000000, 9999999)
|
|
||||||
local p = promise.new()
|
|
||||||
|
|
||||||
-- Store promise data
|
|
||||||
cbData[cbId] = {
|
|
||||||
cb = callback,
|
|
||||||
p = p
|
|
||||||
}
|
|
||||||
|
|
||||||
-- Trigger the server event
|
|
||||||
TriggerServerEvent(clientToServerName, name, cbId, table.unpack(args))
|
|
||||||
|
|
||||||
-- If no callback was provided, wait for the promise and return directly
|
|
||||||
if not hasCallback then
|
|
||||||
local result = Citizen.Await(p)
|
|
||||||
-- If there's only one value, return it directly
|
|
||||||
if #result == 1 then
|
|
||||||
return result[1]
|
|
||||||
else
|
|
||||||
return table.unpack(result)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Otherwise, return nothing (callback will handle it)
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Handle responses from server
|
|
||||||
RegisterNetEvent(clientToServerBackToClientName, function(name, cbId, ...)
|
|
||||||
-- Check for global rebounding callbacks
|
|
||||||
local clientRebound = cbRebounds[name]
|
|
||||||
if clientRebound then
|
|
||||||
clientRebound(...)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Handle the specific callback instance
|
|
||||||
local data = cbData[cbId]
|
|
||||||
if not data then return end
|
|
||||||
|
|
||||||
-- Process callback if provided
|
|
||||||
if data.cb then
|
|
||||||
data.cb(...)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Always resolve the promise with all args for direct returns
|
|
||||||
data.p:resolve({...})
|
|
||||||
cbData[cbId] = nil
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- Handle server requests to client
|
|
||||||
RegisterNetEvent(serverToClientName, function(name, cbId, ...)
|
|
||||||
local data = Callback[name]
|
|
||||||
if not data then return end
|
|
||||||
local func = data.callback
|
|
||||||
if not func then return end
|
|
||||||
|
|
||||||
-- Create response handler
|
|
||||||
TriggerServerEvent(serverToClientBackToServerName, name, cbId, func(...))
|
|
||||||
end)
|
|
||||||
|
|
||||||
exports('RegisterCallback', Callback.Register)
|
|
||||||
exports('RegisterRebound', Callback.RegisterRebound)
|
|
||||||
exports('TriggerCallback', Callback.Trigger)
|
|
||||||
|
|
||||||
return Callback
|
|
||||||
Reference in new issue
Block a user