Reputation: 338
I have searched for an answer to this question without luck. I have only found examples of people passing a callback into a caller function, but haven't seen how the caller actually executes the callback function code internally. If someone could provide me an example and explanation on this it would be much appreciated.
I understand how callbacks work from a functional perspective, I've used them in other languages. I just can't figure out the syntax of how to do it right in lua. I am either executing the callback parameter wrong or passing it into the caller function wrong.
Here is some psudocode of what I am trying to do, just a simple example so I can see it work. (I am a visual learner)
callback = function ()
... do stuff ...
end
function caller(callback)
callback()
end
-- run caller function
caller(callback)
EDIT: I have gotten a few answers saying that my example above works, and it seems like it actually does. Thank you for this, but I suppose I should get more specific considering that my actual code isn't working despite the right syntax.
I am doing some coding for a FiveM server which utilizes essentialmode. I am attempting to use a callback in a script to clean the code up, but it doesn't seem to be firing the callback function. Here are the snippets...
The client script:
RegisterNetEvent("parachute:callback")
AddEventHandler('parachute:callback', function(callback)
print("callback...")
callback()
end)
The server script:
callback = function ()
print("callback fired")
GiveWeaponToPed(GetPlayerPed(-1), GetHashKey("GADGET_PARACHUTE"), 150, true, true)
SetPedComponentVariation(GetPlayerPed(-1), 5, 1, 0, 0)
end
TriggerEvent('es:addCommand', 'callback', function(source, args, user)
TriggerClientEvent("parachute:callback", source, callback)
end, {help = "TEST"})
In the above, the print("callback...")
function executes but the callback()
function does not. I can tell due to the print statements that I added.
For more context to those of you not familiar with essential mode or FiveM scripting, there is a client loaded script and a server loaded script. In the server, TriggerEvent('es:addCommand', ... )
adds a command you can execute using /<cmd name>
. TriggerClientEvent()
kicks off an event on the client via a listener created by RegisterNetEvent()
and AddEventHandler()
. As you can see you pass callbacks to these functions to tell them what to execute when the event is triggered. The callback function itself simply gives a parachute to my character. No parachute is given when I type /callback
however.
What is going wrong if it's not the syntax like I originally thought?
Upvotes: 4
Views: 18269
Reputation: 29214
Functions can be variables in lua, but they are just like any other variable.
I don't know what is wrong with your example, it seems like you have it exactly right. Just entering your code works (try it here).
Update
It appears that FiveM and essentialmode are client/server and running in two different execution environments. They probably serialize data for the communication between the client and server, but passing a function wouldn't work.
There may be something you can do by using loadstring()
... Here's an example you can run at jdoodle:
function sayHi(name)
print("Hello, "..tostring(name).."!")
end
-- create string representation of the function
local functionDef = string.dump(sayHi)
-- convert back to a function
local func = loadstring(functionDef)
func('Jason')
-- or use a string directly, just body, no arguments so
-- we 'return' a function and call it with () after loadstring
-- to get the returned function - [[ ]] is just syntax for a
-- multiline string
local func2 = loadstring([[
return function(name)
print("Hi there, "..tostring(name).."!")
end
]])()
func2('Jason')
String.dump
serializes an existing function as a string and loadstring
converts it back to a function. You could pass this string between the client and server, but it would execute in whatever environment it was executed on. You can also pass a function body, but to get arguments you have to return a function with arguments in that body and call it to get the return value to use that function.
If GiveWeaponToPed
and SetPedComponentVariation
are executed on the client then you could send those commands in place of the 'callback' argument and use loadstring in the client...
client
RegisterNetEvent("parachute:callback")
AddEventHandler('parachute:callback', function(callback)
print("callback...")
loadstring(callback)()
end)
server
codestring = [[
GiveWeaponToPed(GetPlayerPed(-1), GetHashKey("GADGET_PARACHUTE"), 150, true, true)
SetPedComponentVariation(GetPlayerPed(-1), 5, 1, 0, 0)
]]
TriggerEvent('es:addCommand', 'callback', function(source, args, user)
TriggerClientEvent("parachute:callback", source, codestring)
end, {help = "TEST"})
Upvotes: 3
Reputation: 26764
It will work exactly as you described it. You may want to add local
in front of your callback function, but other than that, you should be good. Here is a working example:
local callback = function ()
print("here")
end
function caller(callback)
callback()
end
-- run caller function
caller(callback)
Upvotes: 1