ThePhD / sol2

Sol3 (sol2 v3.0) - a C++ <-> Lua API wrapper with advanced features and top notch performance - is here, and it's great! Documentation:
http://sol2.rtfd.io/
MIT License
4.22k stars 518 forks source link

LuaBind Interopability #1513

Open Causeless opened 1 year ago

Causeless commented 1 year ago

Hey, I am porting a project from LuaBind to Sol3 and was wondering if I could get some help.

We've got a lot of old scripts, and a long history of modding support, so I'm trying to change as little as possible to ensure compatibility.

I've got the usertypes set up correctly, but I've been having issues where Sol is a little too strict with what we're doing:

-- "Test" is a created Sol usertype of type "Activity"
-- We're trying to define an UpdateActivity() function on it, which from the C++ side we can call to tell this object to update

-- UpdateActivity isn't in the lua binding, but we call it from the C++ side
-- Sol doesn't like this, because sol::meta_function::new_index isn't defined

-- ERROR: Data/Base.rte/Activities/Test.lua:7: sol: cannot set (new_index) into this object: no defined new_index operation on usertype
function Test:UpdateActivity()
        -- Sol doesn't like these either
        if self.ValueNotInCppBinding == nil then
            self.ValueNotInCppBinding = 0;
        end
end

Effectively in these cases we're using Lua in "inherit" from the CPP object instead of just binding to it. In LuaBind this worked fine, and accessing any value that wasn't on the object would just work like any normal lua table.

However, this dies due to a lack of sol::meta_function::new_index or sol::meta_function::index being defined. I could define these manually, but I don't want to add a bunch of wrapper stuff to store and track all these objects on the C++ side - I'd prefer to just let Lua handle it all.

I maybe could define these objects as tables, but then we miss out on all the automagic enrolments. It also ended up with a lot of compile errors when I tried this.

Is there a way to set sol::meta_function::new_index/index to fallback to the normal Lua behaviour? Or is there a better way to do this that I'm missing?

Another issue that I've run into is that it appears script cannot construct objects by just doing, for example SolObject(), instead I need to do SolObject.new(). Is there a way to change this? I tried assigning to the call_construct metamethod but it didn't seem to work.

Using luaType.set(sol::call_constructor, sol::constructors<BoundType()>()); seems to work for the construction thing.

Causeless commented 1 year ago

Do I need to use https://github.com/ThePhD/sol2/blob/develop/examples/source/dynamic_object.cpp for this?

It works, but I don't like having this extra junk in our base object instead of letting it be lazily added to the object's lua state. Our objects may or may not be bound to lua, at runtime, so storing this extra map requires adding unnecessary overhead. Preferably we'd be able to just have Lua just handle it the way it normally does as if the usertype was a table.

Also is there a way to simplify class inheritance? In LuaBind I seemed to only have to mark the immediate objects I inherited from, and everything worked. With Sol3, it looks like things are ignored unless I add all bases going down the class heirarchy.

I.E, in LuaBind I could do Object4->Object3->Object2->Object1, and then call functions on Object1 from Object4, as long as I:

~~A. Marked that 4 inherited from 3, 3 from 2, and 2 from 1, and B. Ensured that the luabindings for 1 were instantiated prior to 2, prior to 3, prior to 4 etc.~~

Maybe I'm missing something, but it seems in Sol I need to add all of Object3, Object2, Object1 as bases for every single usertype, which feels very error prone if we do anything that changes the class heirarchy. Admittedly this is partially an issue of bad design and deep OOP chains in our code, but it's an old 2000s era codebase that has many such sins.

Forgive me, I just read https://github.com/ThePhD/sol2/issues/163#issuecomment-238024552. I've been extremely anxiously awaiting for C++ to add compile time reflection. It would be such an incredibly useful feature...