I'm working on game scripting for my engine and am using a metatable to redirect functions from a table (which stores custom functions and data for players) to a userdata object (which is the main implementation for my Player class) so that users may use self
to refer to both.
This is how I do my binding in C# in the Player
class:
state.NewTable("Player"); // Create Player wrapper table
state["Player.data"] = this; // Bind Player.data to the Player class
state.NewTable("mt"); // Create temp table for metatable
state.DoString(@"mt.__index = function(self,key)
local k = self.data[key]
if key == 'data' or not k then
return rawget(self, key)
elseif type(k) ~= 'function' then
print(type(k))
print(k)
return k
else
return function(...)
if self == ... then
return k(self.data, select(2,...))
else
return k(...)
end
end
end
end");
state.DoString("setmetatable(Player, mt)"); // Change Player's metatable
For my Player
class, I implement a method, bool IsCommandActive(string name)
. When I need to call this method using self
, it needs to use the userdata
object, rather than the table, otherwise I get the following error:
NLua.Exceptions.LuaScriptException: 'instance method 'IsCommandActive' requires a non null target object'
For obvious reasons. This is because self
refers to the table, not the userdata. So I implemented a metatable so that it may use self
to refer to either. The implementation is taken from here, but here is my particular variant (my userdata is stored in an index called data
:
mt.__index = function(self,key)
local k = self.data[key]
if key == 'data' or not k then
return rawget(self, key)
elseif type(k) ~= 'function' then
print(type(k))
print(k)
return k
else
return function(...)
if self == ... then
return k(self.data, select(2,...))
else
return k(...)
end
end
end
end
end
Which I follow by using setmetatable
, obviously.
Now to the meat of my question. Notice how I print type(k)
and print(k)
under the elseif
. This is because I noticed that I was still getting the same error, so I wanted to do some debugging. When doing so, I got the following output (which I believe is for IsCommandActive
):
userdata: 0BD47190
Shouldn't it be printing 'function'
? Why is it printing 'userdata: 0BD47190'
? Finally, if that is indeed the case, how can I detect if the value is a C function so I may do the proper redirection?