Lua: How do I execute a callback passed from a parameter?
Solution 1
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"})
Solution 2
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)
ExecutionByFork
Updated on June 04, 2022Comments
-
ExecutionByFork over 1 year
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 thecallback()
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 byRegisterNetEvent()
andAddEventHandler()
. 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?
-
Jason Goemaat over 5 yearsJust a stab, but are you sure the arguments are correct? Can you do a dump of the args along with your
print("callback...")
? Maybe add aprint('callback type: '..type(callback))
and if it's a tablefor k,v in pairs(callback) do print('callback["'..tostring(key).."]: '..tostring(v)) end
-
Jason Goemaat over 5 yearsNot sure how essentialmode works, but it looks like you're declaring a callback function on the server and passing it to the client with the event so that the client can call the function on the server. I doubt that will work, I assume they are isolated enironments.
-
ExecutionByFork over 5 yearsYes, I believe this is why. I overlooked the fact that the server and client had two different address spaces. If you edit your answer to add this in (for completeness) I'll accept yours as the correct answer
-
-
Tom Blodget over 5 yearsTo clarify: There are two kinds of variables, global and local (which includes loop variables and parameters, which can include
self
). And, there are several types of values, including function. Saying "Functions can be variables" or "global…function" sounds odd. Your reasoning is sound though. -
ExecutionByFork over 5 yearsThank you for the feedback, I've updated my question
-
ExecutionByFork over 5 yearsThank you for the feedback, I've updated my question