refractor callbacks
This commit is contained in:
1 parent
a015e681b3
commit
aa1e621f90
1 file changed
+126
-186
+126
-186
@@ -1,197 +1,137 @@
|
||||
Callbacks = {}
|
||||
cbData = {}
|
||||
Callback = Callback or {}
|
||||
local Callback = {}
|
||||
local CallbackRegistry = {}
|
||||
|
||||
--=======================================
|
||||
-- ▀█▀ █▄█ █ █▄ █ █▄▀ ▄▀▄ ██▄ ▄▀▄ █ █ ▀█▀ ▄▀▄ █▀▄ █▀▄ █ █▄ █ ▄▀ █▀▄ █▀▄ ▄▀▄ █▄ ▄█ █ ▄▀▀ ██▀ ▄▀▀ ▀█▀ ▄▀▄ ▄▀▀ ▄▀▄ █ █ ██▄ ▄▀▄ ▄▀▀ █▄▀ ▄▀▀
|
||||
-- █ █ █ █ █ ▀█ █ █ █▀█ █▄█ ▀▄▀ ▀▄█ █ █▀█ █▄▀ █▄▀ █ █ ▀█ ▀▄█ █▀ █▀▄ ▀▄▀ █ ▀ █ █ ▄█▀ █▄▄ ▄█▀ █ ▀▄▀ ▀▄▄ █▀█ █▄▄ █▄▄ █▄█ █▀█ ▀▄▄ █ █ ▄█▀
|
||||
--=======================================
|
||||
-- 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 clientToServerBackToClientName = resource .. ':client:CSC:TriggerCallback'
|
||||
local function handleResponse(registry, name, callbackId, ...)
|
||||
local data = registry[callbackId]
|
||||
if not data then return end
|
||||
|
||||
local serverToClientName = resource .. ':client:SC:TriggerCallback'
|
||||
local serverToClientBackToServerName = resource .. ':server:SCS:TriggerCallback'
|
||||
if data.callback then
|
||||
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)
|
||||
|
||||
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('TriggerCallback', Callback.Trigger)
|
||||
|
||||
-- -- -- -- -- -- -- -- -- --
|
||||
-- ▄▀▀ █ █ ██▀ █▄ █ ▀█▀
|
||||
-- ▀▄▄ █▄▄ █ █▄▄ █ ▀█ █
|
||||
-- -- -- -- -- -- -- -- -- --
|
||||
if IsDuplicityVersion() then return Callback end
|
||||
::client::
|
||||
|
||||
cbRebounds = {}
|
||||
function Callback.Register(name, callback)
|
||||
Callback[name] = {
|
||||
callback = callback,
|
||||
}
|
||||
if not IsDuplicityVersion() then
|
||||
exports('RegisterRebound', Callback.RegisterRebound)
|
||||
end
|
||||
|
||||
function Callback.RegisterRebound(name, 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