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.16k stars 504 forks source link

How can I push an instance of a Class and give it a specific metatable? #1399

Open MillhioreBT opened 2 years ago

MillhioreBT commented 2 years ago

Context: Below you will see a piece of code, as you will notice this is a lua_CFunction

static int luaGameGetPlayers(lua_State* L)
{
    // Game.getPlayers()
    lua_createtable(L, g_game.getPlayersOnline(), 0);

    int index = 0;
    for (const auto& playerEntry : g_game.getPlayers()) {
        pushUserdata<Player>(L, playerEntry.second);
        setMetatable(L, -1, "Player");
        lua_rawseti(L, -2, ++index);
    }
    return 1;
}

This function works as it should, no problem...

Now I want to convert this function and use sol Example:

lua["Game"]["getPlayers"] = [](sol::this_state s) {
    sol::state_view lua(s);
    auto players = lua.create_table(g_game.getPlayersOnline());
    int index = 0;
    auto mt = lua["Player"][sol::metatable_key];
    for (const auto& playerEntry : g_game.getPlayers()) {
        players[++index] = playerEntry.second;
        players[index][sol::metatable_key] = mt;
    }
    return sol::object(lua, sol::in_place, players);
};

When I do the tests in lua, this function returns a table with user data, all correct. however when I try to use the user data, they do not have the metatable that I have indicated that they have. in fact when I try to see what metatable they have, it turns out that they have a metatable with the fields:

__pairs
__name
__type

Sol definitely thinks that I am trying to create a new type of object, but this is not the case, I simply want to fill the table with user data and that this user data has a meta table, I do not need this to create new data types , new objects, new methods, new constructors none of that.

just push user data and give it a metatable without any additional magic, I understand that I can still use my method, but then it just doesn't work to improve other interfaces? if or if I have to build everything with sun from scratch for this to make sense?

In the documentation I read a text that said that if I thought that something could work, I would try it, so that's what I do, although without success.

The g_game.getPlayers() method returns a vector with the players, each player is an instance of the Player class, the lifetime of each instance is managed entirely on the C++ side, how to push these instances to lua? How to grant a meta table to these instances? the normal thing is to push to the stack as follows:

Player** userdata = static_cast<Player**>(lua_newuserdata(L, sizeof(Player*)));
*userdata = *instance_of_player_here;
luaL_getmetatable(L, "Player");
lua_setmetatable(L, -2);