Working with Objects in Lua
Normally, when using push_variant()
or the return value of a GDScript function that Lua calls, the value is copied to Lua. However, types that inherit from Object work a bit differently. Objects will be pushed to Lua as UserData. This means they are passed by reference to or from Lua.
Controlling access to fields and methods
In the background...
In order to call functions and get values from the object we assign the mt_Object metatable to it. This is a custom metatable we defined for Objects. This allows for methods to be called on the object, values to be get/set on the Object and much more.
With the default object metatable
By default every field and method is available to Lua. You can limit what Lua has access to by defining either the lua_fields()
method, which must return an Array of the names of fields/methods. By default this array is treated as a blacklist of methods. If you set permissive to false
, it will be treated as a whitelist instead. The other way to limit access is by defining the __index()
method, which takes reference to the LuaAPI object and a string of the field being requested by Lua. You can then return any value you please to lua.
This is all made possible by the LuaDefaultObjectMetatable assigned to the object_metatable
field on the LuaAPI object by default. For even more control, you can define your own object metatable. See the LuaObjectMetatable class.
Below is an example of passing a Object to Lua:
Overriding metamethods
For some, the previous approach is still too limiting though. So we also allow you to override almost any metamethod on the object.
Note
The first argument passed to the metamethod is always reference to the LuaAPI object. Besides that the arguments will be the same as if you were using it in Lua.
Info
You can learn more about all available metamethods in the official Lua manual.
__index
The __index metamethod is called when Lua tries to get a value from an object. This is when you are using the .index
or the ['index']
operator in Lua. Essentially, this is what the lua_fields()
method is doing. However, you may want to do more than just return a value. You can also raise an error or return a custom value.
The __index method must take two arguments. The first is a reference to the LuaAPI object. The second is the name of the field/method being requested. The method may return the value of the field/method or a LuaError to raise an error.
Here is a example of that:
__newindex
The __newindex metamethod is called when Lua tries to set a value on an object. This is the same as if you were using the =
operator in Lua. Essentially, this is what the lua_fields()
method is doing. However, you may want to do more than just set a value. You can also raise an error or set a custom value.
The __newindex method must take three arguments. The first is a reference to the LuaAPI object. The second is the name of the field/method being set. The third is the value being set. The method may a LuaError to raise an error.
Here is a example of that:
extends Node2D
var lua: LuaAPI
class Player:
var pos = Vector2(1, 0)
# Most metamethods can be overridden. The function names are the same as the metamethods.
func __newindex(ref: LuaAPI, index, value):
if index=="pos":
pos = value
else:
return LuaError.new_error("Invalid index '%s'" % index)
func move_forward():
pos.x+=1
func _ready():
lua = LuaAPI.new()
lua.expose_constructor("Player", Player)
var err = lua.do_string("""
player = Player()
player.pos = Vector2(50, 1)
print(player.pos)
player.move_forward = 5 -- This will cause our custom error
""")
if err is LuaError:
print(err.message)
var player = lua.pull_variant("player")
print(player.pos)