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.06k stars 492 forks source link

Returned Derived Shared Pointer is Nil #1566

Closed Codinablack closed 6 months ago

Codinablack commented 6 months ago

Ok so I have been trying for over a week now to get this thing to work correctly in lua. Initially I kept thinking I am misusing shared pointers somehow, or not properly casting, ect. This turns out to not be the case, and trust me this was extremely infuriating to the point of me considering dropping inheritance all together on these classes and using std::variant to define Creature.

I have a thing class : https://justpaste.it/adxoh I have a creature class that inherits from thing : https://justpaste.it/ajsjo I have a player class that inherits from creature : https://justpaste.it/b7er8

The goal is to make methods such as :getCreature(), getPlayer(), getMonster(), :getNpc() that can be used on any class derived from creature, to return userdata for that specific object IF it is the correct type, IE player:getPlayer() returns userdata, player:getCreature() returns same userdata, but player:getMonster() returns nil, and so on and so forth.

I have been working closely with people in a programmers discord to debug this issue. I ended up adding a c++ test case in my main method like so

    auto player = std::make_shared<Player>();
    player->getPlayer();

Which works perfectly fine. However when using in lua, I get a nil value.

Here is my registration of the usertypes:

void ScriptManager::registerUserTypes() {
    /// constructorlist example.        sol::constructors<vector(),vector(float),void(float, float)>    clist;
    sol::usertype<Thing> thing_type = lua_man.new_usertype<Thing>("Thing", sol::call_constructor, sol::factories([]() {return new Thing(); }));
    thing_type["getItem"] = &Thing::getItem;
    thing_type["getCreature"] = &Thing::getCreature;

    sol::usertype<Creature> creature_type = lua_man.new_usertype<Creature>("Creature", sol::call_constructor, sol::factories([]() {return new Creature(); }));
    creature_type["getCreature"] = &Creature::getCreature;
    creature_type["getPlayer"] = &Creature::getPlayer;
    creature_type[sol::base_classes] = sol::bases<Thing>();

    sol::usertype<Player> player_type = lua_man.new_usertype<Player>("Player", sol::call_constructor, sol::factories([]() {return new Player(); }));
    player_type["getPlayer"] = &Player::getPlayer;
    player_type["getMonster"] = &Player::getMonster;
    player_type["getHealthPoints"] = &Player::getHealthPoints;
    player_type[sol::base_classes] = sol::bases<Creature>();

}

Here is my test.lua script that I use to try to test these methods are working:


print("Loads Test Lua")

local creature = Creature()
local player = Player()

local thing = Thing()

print(thing)

print(player:getHealthPoints())
print(player:getPlayer())
print(player:getMonster())

Here is the output on console:

Creature constructor called :0000024FC84809C0 is thing_ptr data Player constructor called :0000024FC84809C0 is thing_ptr data GetPlayer called 0000024FC84809C0 is thing_ptr data Loads Test Lua Creature constructor called :0000024FC849E8F0 is thing_ptr data Creature constructor called :0000024FC849FCF0 is thing_ptr data Player constructor called :0000024FC849FCF0 is thing_ptr data sol.Thing*: 0000024FC8488BE8 0 GetPlayer called 0000024FC849FCF0 is thing_ptr data nil nil

Things seem to be fine until I call player:getPlayer() in lua. Then I get nil value.

I admit that my knowledge is limited as I am pretty new to cpp, but according to the ai, and the devs in discord, everything should be working just fine on the c++ side, and they are all telling me its most likely a problem with handling of userdata or inheritance in sol2

Codinablack commented 6 months ago

I found the fix.

I need to be making a new object using std::make_shared during the construction of the object to be able to properly reference the shared pointer using "shared_from_this()" and then dynamic cast to the correct type using "shared_from_this()" as the input, since my classes are virtual, the conversion is implicit.

This was very painstaking on my end, on using it with sol2, but the problem was definitely on my end. It is working great now, closing this issue.