Replace actor parameters with thread variables.
This is to provide parameters to loading Actor definitions, in a way that
does not need to be explicitly propagated to nested definitions; I want
loading a sub-definition to remain a simple function call with no mandatory
(prescribed) parameters. This provides a general context to pass information
to Lua about what it's loading, such as LoadingScreen.
These are scoped to the running thread, unlike global variables. This prevents
possible threading problems.
All thread variables are scoped: set a variable, do something, unset it; when
finished, all thread variables are unset.
These are no longer available after load. By design, to use these later,
use upvalues:
local color = lua.GetVar("color");
return Def.Quad {
OnCommand=cmd(diffuse,color);
}
This commit is contained in:
@@ -295,6 +295,147 @@ void LuaManager::RegisterTypes()
|
||||
LUA->Release( L );
|
||||
}
|
||||
|
||||
LuaThreadVariable::LuaThreadVariable( const RString &sName, const RString &sValue )
|
||||
{
|
||||
m_sName = sName;
|
||||
m_pOldValue = new LuaReference;
|
||||
|
||||
Lua *L = LUA->Get();
|
||||
LuaHelpers::Push( L, sValue );
|
||||
SetFromStack( L );
|
||||
LUA->Release( L );
|
||||
}
|
||||
|
||||
LuaThreadVariable::LuaThreadVariable( const RString &sName, LuaReference &Value )
|
||||
{
|
||||
m_sName = sName;
|
||||
m_pOldValue = new LuaReference;
|
||||
|
||||
Lua *L = LUA->Get();
|
||||
Value.PushSelf( L );
|
||||
SetFromStack( L );
|
||||
LUA->Release( L );
|
||||
}
|
||||
|
||||
RString LuaThreadVariable::GetCurrentThreadIDString()
|
||||
{
|
||||
uint64_t iID = RageThread::GetCurrentThreadID();
|
||||
return ssprintf( "%08x%08x", uint32_t(iID >> 32), uint32_t(iID) );
|
||||
}
|
||||
|
||||
bool LuaThreadVariable::PushThreadTable( lua_State *L, bool bCreate )
|
||||
{
|
||||
lua_getfield( L, LUA_REGISTRYINDEX, "LuaThreadVariableTable" );
|
||||
if( lua_isnil(L, -1) )
|
||||
{
|
||||
lua_pop( L, 1 );
|
||||
if( !bCreate )
|
||||
return false;
|
||||
lua_newtable( L );
|
||||
|
||||
lua_pushvalue( L, -1 );
|
||||
lua_setfield( L, LUA_REGISTRYINDEX, "LuaThreadVariableTable" );
|
||||
}
|
||||
|
||||
RString sThreadIDString = GetCurrentThreadIDString();
|
||||
LuaHelpers::Push( L, sThreadIDString );
|
||||
lua_gettable( L, -2 );
|
||||
if( lua_isnil(L, -1) )
|
||||
{
|
||||
lua_pop( L, 1 );
|
||||
if( !bCreate )
|
||||
{
|
||||
lua_pop( L, 1 );
|
||||
return false;
|
||||
}
|
||||
lua_newtable( L );
|
||||
|
||||
lua_pushinteger( L, 0 );
|
||||
lua_rawseti( L, -2, 0 );
|
||||
|
||||
LuaHelpers::Push( L, sThreadIDString );
|
||||
lua_pushvalue( L, -2 );
|
||||
lua_settable( L, -4 );
|
||||
}
|
||||
|
||||
lua_remove( L, -2 );
|
||||
return true;
|
||||
}
|
||||
|
||||
void LuaThreadVariable::GetThreadVariable( lua_State *L )
|
||||
{
|
||||
if( !PushThreadTable(L, false) )
|
||||
{
|
||||
lua_pop( L, 1 );
|
||||
lua_pushnil( L );
|
||||
return;
|
||||
}
|
||||
|
||||
lua_pushvalue( L, -2 );
|
||||
lua_gettable( L, -2 );
|
||||
lua_remove( L, -2 );
|
||||
lua_remove( L, -2 );
|
||||
}
|
||||
|
||||
int LuaThreadVariable::AdjustCount( lua_State *L, int iAdd )
|
||||
{
|
||||
ASSERT( lua_istable(L, -1) );
|
||||
|
||||
lua_rawgeti( L, -1, 0 );
|
||||
ASSERT( lua_isnumber(L, -1) );
|
||||
|
||||
int iCount = lua_tointeger( L, -1 );
|
||||
lua_pop( L, 1 );
|
||||
|
||||
iCount += iAdd;
|
||||
lua_pushinteger( L, iCount );
|
||||
lua_rawseti( L, -2, 0 );
|
||||
|
||||
return iCount;
|
||||
}
|
||||
|
||||
void LuaThreadVariable::SetFromStack( lua_State *L )
|
||||
{
|
||||
ASSERT( !m_pOldValue->IsSet() ); // don't call twice
|
||||
|
||||
PushThreadTable( L, true );
|
||||
|
||||
lua_getfield( L, -1, m_sName );
|
||||
m_pOldValue->SetFromStack( L );
|
||||
|
||||
lua_pushvalue( L, -2 );
|
||||
lua_setfield( L, -2, m_sName );
|
||||
|
||||
AdjustCount( L, +1 );
|
||||
|
||||
lua_pop( L, 2 );
|
||||
}
|
||||
|
||||
LuaThreadVariable::~LuaThreadVariable()
|
||||
{
|
||||
Lua *L = LUA->Get();
|
||||
|
||||
PushThreadTable( L, true );
|
||||
m_pOldValue->PushSelf( L );
|
||||
lua_setfield( L, -2, m_sName );
|
||||
|
||||
if( AdjustCount( L, -1 ) == 0 )
|
||||
{
|
||||
// if empty, delete the table
|
||||
lua_getfield( L, LUA_REGISTRYINDEX, "LuaThreadVariableTable" );
|
||||
ASSERT( lua_istable(L, -1) );
|
||||
|
||||
LuaHelpers::Push( L, GetCurrentThreadIDString() );
|
||||
lua_pushnil( L );
|
||||
lua_settable( L, -3 );
|
||||
lua_pop( L, 1 );
|
||||
}
|
||||
lua_pop( L, 1 );
|
||||
|
||||
LUA->Release( L );
|
||||
|
||||
delete m_pOldValue;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
@@ -712,9 +853,18 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
static int GetThreadVariable( lua_State *L )
|
||||
{
|
||||
luaL_checkstring( L, 1 );
|
||||
lua_pushvalue( L, 1 );
|
||||
LuaThreadVariable::GetThreadVariable( L );
|
||||
return 1;
|
||||
}
|
||||
|
||||
const luaL_Reg luaTable[] =
|
||||
{
|
||||
LIST_METHOD( ReadFile ),
|
||||
LIST_METHOD( GetThreadVariable ),
|
||||
{ NULL, NULL }
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ typedef lua_State Lua;
|
||||
typedef void (*RegisterWithLuaFn)(lua_State*);
|
||||
class RageMutex;
|
||||
class XNode;
|
||||
class LuaReference;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
@@ -121,6 +122,26 @@ namespace LuaHelpers
|
||||
inline int AbsIndex( Lua *L, int i ) { if( i > 0 || i <= LUA_REGISTRYINDEX ) return i; return lua_gettop( L ) + i + 1; }
|
||||
}
|
||||
|
||||
class LuaThreadVariable
|
||||
{
|
||||
public:
|
||||
LuaThreadVariable( const RString &sName, const RString &sValue );
|
||||
LuaThreadVariable( const RString &sName, LuaReference &Value );
|
||||
~LuaThreadVariable();
|
||||
static void GetThreadVariable( lua_State *L );
|
||||
|
||||
private:
|
||||
LuaThreadVariable( const LuaThreadVariable &cpy ); // not defined
|
||||
|
||||
void SetFromStack( lua_State *L );
|
||||
int AdjustCount( lua_State *L, int iAdd );
|
||||
static bool PushThreadTable( lua_State *L, bool bCreate );
|
||||
static RString GetCurrentThreadIDString();
|
||||
|
||||
RString m_sName;
|
||||
LuaReference *m_pOldValue;
|
||||
};
|
||||
|
||||
/* Iterate over all elements in the table. For safety reasons, the key is pushed onto
|
||||
* the stack and can be read (safely) as a string and popped or altered in any way.
|
||||
* Stack management is handled automatically. That is, you need not remove all stack
|
||||
|
||||
Reference in New Issue
Block a user