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?