Reputation: 11
I Want Create a Table Like This, a Table contains Player Userdata
PlayerList = { player1, player2, ...}
small part my code like this
int Player::GetLocal(lua_State* L){
auto p = lua_newuserdata(L, sizeof(NativePlayer));
new (p) NativePlayer();
p->data = global::get_local();
luaL_getmetatable(L, "PlayerMetaTable");
lua_setmetatable(L, -2);
return 1;
}
int Player::ToList(lua_State* L) {
lua_newtable();
GameLogic* gameLogic = global::get_game_logic();
for (auto it = gameLogic->PlayerList.begin(); it != gameLogic->PlayerList.end(); ++it) {
lua_pushinteger(L, index);
auto p = lua_newuserdata(L, sizeof(NativePlayer));
new (p) NativePlayer();
p->data = *it;
luaL_getmetatable(L, "PlayerMetaTable");
lua_setmetatable(L, -4);
lua_settable(L, -3);
}
return 1;
}
the problem is the data type in the table is not NativePlayerMetatable
instead PlayerList
Becomes NativePlayerMetatable
I want the PlayerList
to remain a table, and its members are NativePlayerMetatable
currentPlayer = Player.GetLocal()
PlayerList = Player.ToList()
print(currentPlayer)
print(PlayerList[0])
print(PlayerList[1])
print(PlayerList)
Output:
PlayerMetaTable: 000002607203F590
userdata: 0000026079E901D8
userdata: 0000026079EA1A08
PlayerMetaTable: 000002607203F7FF
The Output I want
PlayerMetaTable: 000002607203F590
PlayerMetaTable: 0000026079E901D8
PlayerMetaTable: 0000026079EA1A08
table: 000002607203F7FF
Upvotes: 1
Views: 499
Reputation: 741
At the point where you call lua_setmetatable(L, -4)
in Player::ToList
, you have added four objects to the stack. When things are added to the stack, they go on top. We can look backwards to see what's on the stack. Starting from the top, we have first the metatable pushed by luaL_getmetatable
, second the player userdata pushed by lua_newuserdata
, third the index pushed by lua_pushinteger
, and fourth the player list pushed by lua_newtable
. (And, none of these values have be popped from the stack yet.)
(In general, we might worry about additional values pushed by previous iterations of the loop, but your loop pushes three values and also pops three values, so no values from any previous iteration will remain -- this is usually good, as a loop that pushes more values than it pops might eventually overflow unless you grow the stack, and a loop that pops more values than it pushes might underflow.)
Negative indices count backwards from the top of the stack. So, again at the point of the lua_setmetatable(L, -4)
call, -1
would refer to the metatable, -2
to the player userdata, -3
to the index, and -4
to the player list. Because you are passing -4
, you are assigning the metatable to the player list. To assign the metatable to the player userdata, you would use index -2
instead.
If you find negative indices hard to keep track of, you could consider using positive indices instead. When using positive indices, you may not want to use numbers directly as you may not know the size of the stack to begin with. (For example, in a C function called directly via Lua, which is probably the case for the functions you have exhibited, the stack will initially contain any arguments that were passed to the function, and it would be sloppy to assume that no parameters were passed without checking, even if you don't expect parameters.) You can use lua_gettop
to find the index of the element at the top of the stack. E.g.
lua_newtable(L);
const int list_index = lua_gettop(L);
... and later ...
auto p = lua_newuserdata(L, sizeof(NativePlayer));
const int player_index = lua_gettop(L);
new (p) NativePlayer();
p->data = *it;
luaL_getmetatable(L, "PlayerMetaTable");
lua_setmetatable(L, player_index);
lua_settable(L, list_index);
But, this does not mean you can ignore the stack altogether as, e.g. you need to know the top of the stack when you return (although a sloppy implementation could push another copy of the value it wants to return just before returning), and many of the API functions like lua_setmetatable
and lua_settable
deal directly with values on top of the stack (even if they also take indices).
Upvotes: 0