lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Date: Thu, 01 Sep 2005 08:18:21 +0200
From: Mario <www.derfordfahrer@gmx.de>
Subject: calling fcuntion from other lua context
To: lua@bazar2.conectiva.com.br
Message-ID: <43169D2D.7000806@gmx.de>
Content-Type: text/plain; charset=us-ascii

Hi all!

I have some c++ objects, all with their own lua context. How is it
possible to call a lua function from one lua context to an another one?
For example:


script 1:
function CObject:OnLogic( )

 local a = wmanager:getEntityByName( "NewObject" );
 a:some_function( )

end


script 2:
function CObject:OnLogic( )
-- do nothing
end

function CObject:some_function( )
io.write("Hi there!\n")
end

I'm getting the error message "attempt to call method `some_function' (a
nil value)"?

Thank you in advance!
Greetings Mario


Today I was just "solving" the same problem myself. It is really complicated and not easy to do imho. Here is a snippet of code that I made which does it although it has a limitation in that you can only pass and return arguments that are bool, string, number or nil... although the code could be exanded to do more. Some of the code contains stuff my personal library I called bindlua, but I think it might at least give you something you can work with.

int lua_state_to_state_func_call(lua_State* L)
{
lua_State* LO = static_cast<lua_State*>(lua_touserdata(L, upvalueindex<1>::VAL));
const char* func = lua_tostring(L, upvalueindex<2>::VAL);

const int LO_origTop = lua_gettop(LO);
lua_pushstring(LO, func);
lua_gettable(LO, LUA_GLOBALSINDEX);
// the func to call is now on top of LO
// Now put the args on LO, they r current in L

bool error = false;
const int args = lua_gettop(L);
for(int i = 1; i <= args; ++i)
{
 if(lua_type(L, i) == LUA_TSTRING)
 {
  const char* s = lua_tostring(L, i);
  lua_pushstring(LO, s);
 }
 else if(lua_type(L, i) == LUA_TNUMBER)
 {
  lua_Number n = lua_tonumber(L, i);
  lua_pushnumber(LO, n);
 }
 else
 {
  std::ostringstream oss;
oss << "state to state func call does not support arg (" << i << ") type: " << lua_typename(L, lua_type(L, i));
  lua_warning(L, oss.str());
  error = true;
 }
}

if(error)
{
 lua_settop(LO, LO_origTop);
 return 0;
}

try
{
 lua_pcall(LO, args, LUA_MULTRET, 0);
 const int results = lua_gettop(LO) - LO_origTop;
 for(int i = LO_origTop + 1; i <= lua_gettop(LO); ++i)
 {
  if(lua_type(LO, i) == LUA_TSTRING)
  {
   const char* s = lua_tostring(LO, i);
   lua_pushstring(L, s);
  }
  else if(lua_type(LO, i) == LUA_TNUMBER)
  {
   lua_Number n = lua_tonumber(LO, i);
   lua_pushnumber(L, n);
  }
  else
  {
   std::ostringstream oss;
oss << "state to state func call does not support ret val type: " << lua_typename(LO, lua_type(LO, i));
   lua_warning(LO, oss.str());
   return 0;
  }
 }

 lua_settop(LO, LO_origTop);
 return results;
}
catch(bindlua_exception& e)
{
 lua_warning(L, e.what());
}
}

// Here pScr is an object which olds the state of the "other object"
// L is the state that is calling a function in the other ob
// ie: x = ob.SomeFunc(1,2,3);
// ob is a userdata holding pScr, and through some code of my bindlua library you eventually get to this // unhanded_get code, which makes a dispatch to the state_to_state_func_call above
template<>
int unhandled_get(const Interface::ScriptPtr& pScr, const std::string& key, lua_State* L)
{
bindlua::lua_state LB = pScr->GetState();
lua_getglobal(LB, key);
if(lua_isnil(LB, -1))
{
 lua_pop(LB, 1);
 return 0;
}
if(lua_type(LB, -1) == LUA_TFUNCTION)
{
 lua_pushlightuserdata(L, LB.get());
 lua_pushstring(L, key);
 lua_pushcclosure(L, lua_state_to_state_func_call, 2);
 return 1;
}
if(lua_type(LB, -1) == LUA_TSTRING)
{
 std::string s = lua_tostring(LB, -1);
 lua_pushstring(L, s);
 return 1;
}
std::ostringstream oss;
oss << "unsupported type in script to script transfer, type: " << lua_typename(LB.get(), lua_type(LB.get(), -1));
lua_warning(L, oss.str());
return 0;
}