I'm creating some UI for a game I'm currently working on in C#, and want to expose everything down to Lua so that my artist can make small tweaks without needing to do anything in code. I'm using MoonSharp for integrating Lua scripts into my project.
Here is what I currently have for my UIElement wrapper class:
UIElement = {};
UIElement.__index = UIElement;
setmetatable( UIElement, {
__index = function( self, key )
local codeElement = rawget( self, "__codeElement" );
local field = codeElement and codeElement[key];
if type( field ) == "function" then
return function( obj, ... )
if obj == self then
return field( codeElement, ... );
else
return field( obj, ... )
end
end;
else
return field;
end
end,
__call = function( cls, ... )
return cls.new( ... );
end,
} );
function UIElement.new()
local self = setmetatable( {}, UIElement );
self.__codeElement = BLU_UIElement.__new();
return self;
end
BLU_UIElement is my C# class which is exposed to Lua via the MoonSharp API. It works properly when working directly with the object, and has functions like SetPos, SetColor, etc.
UIElement is intended to be my "class" in Lua to wrap and extended my C# object.
When I instantiate a UIElement elsewhere in script and attempt to call a function (SetPos for example), it does correctly get into the __index function. However, the rawget call always returns nil. It doesn't seem specific to the BLU_UIElement either. I have already tried something very simple like adding a string ID value in the constructor and trying to rawget it in the __index function, but it also returns nil.
I'm assuming I'm just doing something incorrectly setting up the metastable on either the class or the object itself, but I'm not exactly sure where the problem lies. I've been looking here: http://lua-users.org/wiki/ObjectOrientationTutorial for an idea on what I'm doing wrong, but nothing jumps out on me.
I appreciate any guidance on this, I've been looking at this for a couple days without figuring it out, and searching online generally just shows similar code to what I am already doing.
I had a friend who is far more experienced with Lua metatables than I am take a look. Posting the answer here in case it helps anyone else.
The issue was that I was trying to use the UIElement table as both the "class" table as well as the "object" metatable. When calling rawget inside the __index function, it was attempting to find things in the UIElement table instead of the self table created in UIElement.new(). Splitting these two into distinct tables (one for the class, one for the object metatable) fixed things.
Here is my updated and working code:
UIElement = {};
setmetatable( UIElement, {
__call = function( cls, ... )
return cls.new( ... );
end,
} );
UIElement.objectMetaTable = {
__index = function( self, key )
local objectValue = rawget(self, key);
if objectValue ~= nil then
return objectValue;
end
local classValue = UIElement[key];
if classValue ~= nil then
return classValue;
end
local codeElement = rawget(self, "__codeElement");
if codeElement then
return codeElement[key];
end
end,
};
function UIElement.new()
local newInstance = setmetatable( { id = "blah" }, UIElement.objectMetaTable );
newInstance.__codeElement = BLU_UIElement.__new();
return newInstance;
end