lua-gdextension icon indicating copy to clipboard operation
lua-gdextension copied to clipboard

Question - Add lua hook to Callable/LuaFunction

Open Hestia-SGG opened this issue 8 months ago • 4 comments

Would the ability to add hooks to Callables/LuaFunctions be possible? Being able to set hooks to callbacks in GDScript would be useful, as it would allow for interrupting infinitely running threads or writing debuggers, and even running lua code line by line. SOL2 supports hooks through lua_sethook and an example can be found here: Interrupting Execution. Some more information can be found here: Killing the code from the outside.... However, I'm not sure how it could wrap from Callables/LuaFunction to the C-style function lua_sethook requires.

Hestia-SGG avatar May 06 '25 15:05 Hestia-SGG

Would the ability to add hooks to Callables/LuaFunctions be possible?

Yes, absolutely.

However, I'm not sure how it could wrap from Callables/LuaFunction to the C-style function lua_sethook requires.

We can totally do what Lua's debug.sethook does and store callbacks in the registry. Its implementation store a table with one callback for each event type, which the hook function then calls if the event match. Not sure we need that level of flexibility, though, we could just keep a single Callable 🤔 But we could also do exactly what debug.sethook does, making it possible for hooks from Lua to coexist with hooks from GDScript, one for each event type.

gilzoide avatar May 06 '25 16:05 gilzoide

Oh yeah, and of course, if you open the debug library in your LuaState, you can manually call debug.sethook with your hook function (it must be a LuaFunction, not a Callable, Lua checks for argument type in its implementation).

Something like this (disclaimer: not tested):

# "c" is "function call" event
lua_state.globals.debug.sethook(lua_state.create_function(my_callable), "c")

gilzoide avatar May 06 '25 17:05 gilzoide

Thank you for the info! I was wondering if accessing the debug sethook would work, and was going to test by injecting it through lua code, but that is so much better! For now I'm going to test what you gave above, but it looks like it would work fine.

We can totally do what Lua's debug.sethook does and store callbacks in the registry

If I felt smarter I'd try adding myself the way you described here and do a PR, but I am not that well versed in the C/C++ lua bindings.

Hestia-SGG avatar May 06 '25 18:05 Hestia-SGG

After doing some testing, I was able to get it working with a small tweak:

# this must have two parameters to work
func debug_hook_func(reason, line_num):
	print("Hook called!")

func _ready():
	# ...
	# init lua_state here with LIB_DEBUG
	# ...
	var lua_debug_hook_wrapper = lua_state.create_function(debug_hook_func)
	 # the number at the end may be left off, but to do every x lines, it must be a float, not an int
	lua_state.globals.debug.sethook.invoke(lua_debug_hook_wrapper, "", 100.0)

Hestia-SGG avatar May 06 '25 18:05 Hestia-SGG