refractor callbacks

This commit is contained in:
JericoFX committed 2025-05-05 15:49:03 -03:00
1 parent a015e681b3
commit aa1e621f90
1 file changed
+127 -187
+127 -187
View File
@@ -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
return Callback