Returning a lua table on SWIG call
I have a class with a method called GetEnemiesLua. I have bound this class to lua using SWIG, and I can call this method using my lua code.
I am trying to get the method to return a lua table of objects.
Here is my current code:
void CGame::GetEnemiesLua(){
std::vector<Unit*> enemies = callback->GetEnemyUnits();
if( enemies.empty()){
lua_pushnil(ai->L);
return;
} else{
lua_newtable(ai->L);
int top = lua_gettop(ai->L);
int index = 1;
for (std::vector<Unit*>::iterator it = enemies.begin(); it != enemies.end(); ++it) {
//key
lua_pushinteger(ai->L,index);//lua_pushstring(L, key);
//value
CUnit* unit = new CUnit(callback,*it,this);
ai->PushIUnit(unit);
开发者_运维百科lua_settable(ai->L, -3);
++index;
}
::lua_pushvalue(ai->L,-1);
}
}
PushIUnit is as follows:
void CTestAI::PushIUnit(IUnit* unit){
SWIG_NewPointerObj(L,unit,SWIGTYPE_p_IUnit,1);
}
To test this I have the following code:
t = game:GetEnemiesLua()
if t == nil then
game:SendToConsole("t is nil! ")
end
The result is always 't is nil', despite this being incorrect. I have put breakpoints in the code and it is indeed going over the loop, rather than doing lua_pushnil
.
So how do I make my method return a table when called via lua?
Your 'GetEnemies' function returns void which SWIG will take literally, throwing away any values you attempt to return. You'll want to specify your C function to either return an array or take a pointer to one.
For example,
std::vector<Unit*>& CGame::GetEnemiesLua()
{
return callback->GetEnemyUnits();
}
Next, tell SWIG how to interpret this out value:
// convert the return value into a Lua table
%typemap(argout, noblock=1) std::vector<Unit*>&
{
SWIG_arg += ConvertEnemyVectorToLuaTable(*$1);
}
Your conversion should return '1' to indicate you pushed a single table onto the stack.
int ConvertEnenyVectorToLuaTable(std::vector<Unit*>& enemies)
{
if(enemies->empty())
{
lua_pushnil(ai->L);
return 1; // you did push a NIL value
}
else
{
lua_newtable(ai->L);
int top = lua_gettop(ai->L);
int index = 1;
for (std::vector<Unit*>::iterator it = enemies.begin();
it != enemies.end();
++it)
{
//key
lua_pushinteger(ai->L,index);
//value
ai->PushIUnit(*it);
// set the table entry
lua_settable(ai->L, -3);
++index;
}
// push the new table
::lua_pushvalue(ai->L,-1);
return 1;
}
}
God only knows what SWIG is doing (the Lua API is so simple that I avoid SWIG and its little friends), but somewhere you need to communicate to Lua that you are not only leaving a table on the top of the stack, but that you want to return that table. If you were writing the C code yourself return 1;
would do it. I don't know how to persuade SWIG to get it to return a value for you, but I bet a return type of void
is not doing you any favors.
You might try working around SWIG and just create a function with prototype
int lua_get_enemies(lua_State *L);
If you can then get your inner stuff to work, just ending the routine with return 1;
and the table on the top of the stack might do it.
精彩评论