Seeing as whenever I finish getting my framework rewritten for PR it will more than likely have the single most comprehensive callback system in the FiveM Ecospace, I’m gonna take a wild guess and say ESX doesn’t hold a trademark over callbacks.
Might I recommend that you write in the ability to send data via your callbacks. I’ve found it superrrrrr useful in my callback system being able to send data to the server via client to server callbacks and sending data to the client via server to client callbacks. I’ve mainly used it for checking if code on one side matches the other (mainly used to combat lua injectors editing client side code), but I’ve also found it handy doing other things as well.
[Example]
Callbacks:TriggerCallback('Mechanic:GetShopData', function(data)
Data.CurrentShopInfo = data
end, Data.CurrentShop)
I can have 1 callback that handles getting the shop data, and I can send the current shop the player is at and pull data like that, rather than having a different callback for each shop.
Callbacks:TriggerCallback('Mechanic:GetShopData', function(data)
Data.CurrentShopInfo = data
end, Data.CurrentShop)
Callbacks:RegisterCallback('Mechanic:GetShopData', function(data, cb)
if data == 'Bennys' then
cb(Data.Shops.Bennys)
elseif data == 'LSCustoms' then
cb(Data.Shops.LSCustoms)
end
end)
So I’m sending Data.CurrentShop to the server inside the callback code. This is the shop that the player is currently at. I’m then sending back the data from that shop via the cb() and assigning it to Data.CurrentShopInfo. Instead of having a separate callback for each location, I have just one that handles them all. Data is the just table name that I use on all my resources to handle any data for the client/server (tables, variables, etc.)
I can add that behavior but callbacks are made for cross side not same side, if you use it for same side you can create conflicts or it can be less safe because you can make fake server callbacks.
This is the same as just using AddEventHandler
Example:
function GetShopData(data, cb)
if cb then cb(Data.Shops[data]) end
return Data.Shops[data]
-- adding those if-statement was inefficient and a waste of lines
end
AddEventHandler('Mechanic:GetShopData', GetShopData)
RegisterServerCallback('Mechanic:GetShopData', GetShopData)
Idk what you mean by same side and cross side. I assume cross side = client to server or vice versa by the sounds of it.
In the example I posted above, Callbacks:RegisterCallback is done serverside and Callbacks:TriggerCallback is clientside. It’s not possible to fake code thats written on the server…so I’m a little confused by what you’re saying.
SERVER =======================
self.spawn = function(playerId)
if self.vSpawn == 0 then
if self.vProprio == ESX.Players[playerId].identifier or ESX.Players[playerId].pAdmin > 7 then
local entity = TriggerClientCallback(playerId, 'spawnSonVehicle', self);
if entity then
self.vEntity = entity;
self.vSpawn = 1;
--ESX.Players[playerId].chatMsg(self.vSqlID.." - ".. self.vData.name.." spawn /v ranger", ESX.colors.VALID)
ESX.Players[playerId].notifyPF(self.vData.name.." ~g~spawn ~y~/v ranger", 1);
end
else ESX.Players[playerId].chatMsg("Véhicule ID "..self.vSqlID .." ne vous appartient pas", ESX.colors.STOP) end
else ESX.Players[playerId].chatMsg(self.vData.name.." déjà spawn /v localiser", ESX.colors.STOP) end
end
CLIENT =======================
local spawnActive = 0;
RegisterClientCallback('spawnSonVehicle', function(data, ...)
local vehicle = nil;
if spawnActive == 0 then
spawnActive = 1;
local vehicleName = data.vData.name;
local model = (type(vehicleName) == 'number' and vehicleName or GetHashKey(vehicleName))
local coords = data.vPos;
if IsModelInCdimage(model) then
ESX.RequestModel(model)
vehicle = CreateVehicle(model, coords.x, coords.y, coords.z, coords.heading, true, false)
local networkId = NetworkGetNetworkIdFromEntity(vehicle)
SetNetworkIdCanMigrate(networkId, true)
SetEntityAsMissionEntity(vehicle, true, false)
SetVehicleHasBeenOwnedByPlayer(vehicle, true)
SetVehicleNeedsToBeHotwired(vehicle, false)
SetVehRadioStation(vehicle, 'OFF')
SetModelAsNoLongerNeeded(model)
ESX.Game.SetVehicleProperties(vehicle, data.vData);
SetVehicleEngineOn(vehicle, false, false, true);
Citizen.SetTimeout(5000, function()
spawnActive = 0;
end)
else TriggerEvent('chat:addMessage', {args = {"Véhicule ID ".. data.vSqlID .." non identifié."}}) end
end
while not vehicle do
Wait(10)
end
return vehicle;
end)