void CLuaArguments::ReadTable(lua_State* luaVM, int iIndexBegin, CFastHashMap<const void*, CLuaArguments*>* pKnownTables) { bool bKnownTablesCreated = false; if (!pKnownTables) { pKnownTables = new CFastHashMap<const void*, CLuaArguments*>(); bKnownTablesCreated = true; } pKnownTables->insert(std::make_pair(lua_topointer(luaVM, iIndexBegin), this)); // Delete the previous arguments if any DeleteArguments(); LUA_CHECKSTACK(luaVM, 2); lua_pushnil(luaVM); /* first key */ if (iIndexBegin < 0) iIndexBegin--; while (lua_next(luaVM, iIndexBegin) != 0) { /* uses 'key' (at index -2) and 'value' (at index -1) */ CLuaArgument* pArgument = new CLuaArgument(luaVM, -2, pKnownTables); m_Arguments.push_back(pArgument); // push the key first pArgument = new CLuaArgument(luaVM, -1, pKnownTables); m_Arguments.push_back(pArgument); // then the value /* removes 'value'; keeps 'key' for next iteration */ lua_pop(luaVM, 1); } if (bKnownTablesCreated) delete pKnownTables; }
bool CLuaArguments::CallGlobal ( CLuaMain* pLuaMain, const char* szFunction, CLuaArguments * returnValues ) const { assert ( pLuaMain ); assert ( szFunction ); TIMEUS startTime = GetTimeUs (); // Add the function name to the stack and get the event from the table lua_State* luaVM = pLuaMain->GetVirtualMachine (); assert ( luaVM ); LUA_CHECKSTACK ( luaVM, 1 ); int luaStackPointer = lua_gettop ( luaVM ); lua_pushstring ( luaVM, szFunction ); lua_gettable ( luaVM, LUA_GLOBALSINDEX ); // Push our arguments onto the stack PushArguments ( luaVM ); // Call the function with our arguments pLuaMain->ResetInstructionCount (); int iret = 0; try { iret = lua_pcall ( luaVM, m_Arguments.size (), LUA_MULTRET, 0 ); } catch ( ... ) { return false; } if ( iret == LUA_ERRRUN || iret == LUA_ERRMEM ) { std::string strRes = ConformResourcePath ( lua_tostring( luaVM, -1 ) ); g_pGame->GetScriptDebugging()->LogError ( luaVM, "%s", strRes.c_str () ); // cleanup the stack while ( lua_gettop ( luaVM ) - luaStackPointer > 0 ) lua_pop ( luaVM, 1 ); return false; // the function call failed } else { int iReturns = lua_gettop ( luaVM ) - luaStackPointer; if ( returnValues != NULL ) { for ( int i = - iReturns; i <= -1; i++ ) { returnValues->ReadArgument ( luaVM, i ); } } // cleanup the stack while ( lua_gettop ( luaVM ) - luaStackPointer > 0 ) lua_pop ( luaVM, 1 ); } CPerfStatLuaTiming::GetSingleton ()->UpdateLuaTiming ( pLuaMain, szFunction, GetTimeUs() - startTime ); return true; }
bool CLuaArguments::Call ( CLuaMain* pLuaMain, int iLuaFunction, CLuaArguments * returnValues ) const { assert ( pLuaMain ); // Add the function name to the stack and get the event from the table lua_State* luaVM = pLuaMain->GetVirtualMachine (); assert ( luaVM ); LUA_CHECKSTACK ( luaVM, 1 ); int luaStackPointer = lua_gettop ( luaVM ); lua_getref ( luaVM, iLuaFunction ); // Push our arguments onto the stack PushArguments ( luaVM ); // Call the function with our arguments pLuaMain->ResetInstructionCount (); int iret = lua_pcall ( luaVM, m_Arguments.size (), LUA_MULTRET, 0 ); if ( iret == LUA_ERRRUN || iret == LUA_ERRMEM ) { const char* szRes = lua_tostring( luaVM, -1 ); g_pGame->GetScriptDebugging()->LogError ( luaVM, "%s", szRes ); // cleanup the stack while ( lua_gettop ( luaVM ) - luaStackPointer > 0 ) lua_pop ( luaVM, 1 ); return false; // the function call failed } else { int iReturns = lua_gettop ( luaVM ) - luaStackPointer; if ( returnValues != NULL ) { for ( int i = - iReturns; i <= -1; i++ ) { returnValues->ReadArgument ( luaVM, i ); } } // cleanup the stack while ( lua_gettop ( luaVM ) - luaStackPointer > 0 ) lua_pop ( luaVM, 1 ); } return true; }
void CLuaArguments::PushAsTable(lua_State* luaVM, CFastHashMap<CLuaArguments*, int>* pKnownTables) { // Ensure there is enough space on the Lua stack LUA_CHECKSTACK(luaVM, 4); bool bKnownTablesCreated = false; if (!pKnownTables) { pKnownTables = new CFastHashMap<CLuaArguments*, int>(); bKnownTablesCreated = true; lua_newtable(luaVM); // using registry to make it fail safe, else we'd have to carry // either lua top or current depth variable between calls lua_setfield(luaVM, LUA_REGISTRYINDEX, "cache"); } lua_newtable(luaVM); // push it onto the known tables int size = pKnownTables->size(); lua_getfield(luaVM, LUA_REGISTRYINDEX, "cache"); lua_pushnumber(luaVM, ++size); lua_pushvalue(luaVM, -3); lua_settable(luaVM, -3); lua_pop(luaVM, 1); pKnownTables->insert(std::make_pair((CLuaArguments*)this, size)); vector<CLuaArgument*>::const_iterator iter = m_Arguments.begin(); for (; iter != m_Arguments.end() && (iter + 1) != m_Arguments.end(); ++iter) { (*iter)->Push(luaVM, pKnownTables); // index ++iter; (*iter)->Push(luaVM, pKnownTables); // value lua_settable(luaVM, -3); } if (bKnownTablesCreated) { // clear the cache lua_pushnil(luaVM); lua_setfield(luaVM, LUA_REGISTRYINDEX, "cache"); delete pKnownTables; } }
bool CMapEventManager::Call ( const char* szName, const CLuaArguments& Arguments, class CClientEntity* pSource, class CClientEntity* pThis ) { // Check if no events if ( !m_bHasEvents ) return false; // Check if no events with a name match EventsIterPair itPair = m_EventsMap.equal_range ( szName ); if ( itPair.first == itPair.second ) return false; TIMEUS startTimeCall = GetTimeUs (); SString strStatus; // Check for multi-threading slipups assert ( IsMainThread () ); // Call all the events with matching names bool bCalled = false; bool bIsAlreadyIterating = m_bIteratingList; m_bIteratingList = true; // Copy the results into a array in case m_EventsMap is modified during the call std::vector< CMapEvent* > matchingEvents; for ( EventsIter iter = itPair.first ; iter != itPair.second ; ++iter ) matchingEvents.push_back(iter->second); for ( std::vector< CMapEvent* >::iterator iter = matchingEvents.begin() ; iter != matchingEvents.end() ; ++iter ) { CMapEvent* pMapEvent = *iter; // If it's not being destroyed if ( !pMapEvent->IsBeingDestroyed () ) { // Compare the names dassert ( strcmp ( pMapEvent->GetName (), szName ) == 0 ); { // Call if propagated? if ( pSource == pThis || pMapEvent->IsPropagated () ) { // Grab the current VM lua_State* pState = pMapEvent->GetVM ()->GetVM (); LUA_CHECKSTACK ( pState, 1 ); // Ensure some room #if MTA_DEBUG int luaStackPointer = lua_gettop ( pState ); #endif TIMEUS startTime = GetTimeUs(); // Aspect ratio adjustment bodges if ( pMapEvent->ShouldAllowAspectRatioAdjustment() ) { g_bAllowAspectRatioAdjustment = true; if ( pMapEvent->ShouldForceAspectRatioAdjustment() ) g_pCore->GetGraphics()->SetAspectRatioAdjustmentEnabled( true ); } // Record event for the crash dump writer static bool bEnabled = ( g_pCore->GetDiagnosticDebug () == EDiagnosticDebug::LUA_TRACE_0000 ); if ( bEnabled ) g_pCore->LogEvent ( 0, "Lua Event", pMapEvent->GetVM ()->GetScriptName (), szName ); // Store the current values of the globals lua_getglobal ( pState, "source" ); CLuaArgument OldSource ( pState, -1 ); lua_pop( pState, 1 ); lua_getglobal ( pState, "this" ); CLuaArgument OldThis ( pState, -1 ); lua_pop( pState, 1 ); lua_getglobal ( pState, "sourceResource" ); CLuaArgument OldResource ( pState, -1 ); lua_pop( pState, 1 ); lua_getglobal ( pState, "sourceResourceRoot" ); CLuaArgument OldResourceRoot ( pState, -1 ); lua_pop( pState, 1 ); lua_getglobal ( pState, "eventName" ); CLuaArgument OldEventName ( pState, -1 ); lua_pop( pState, 1 ); // Set the "source", "this", "sourceResource" and the "sourceResourceRoot" globals on that VM lua_pushelement ( pState, pSource ); lua_setglobal ( pState, "source" ); lua_pushelement ( pState, pThis ); lua_setglobal ( pState, "this" ); CLuaMain* pLuaMain = g_pClientGame->GetScriptDebugging()->GetTopLuaMain(); CResource* pSourceResource = pLuaMain ? pLuaMain->GetResource() : NULL; if ( pSourceResource ) { lua_pushresource ( pState, pSourceResource ); lua_setglobal ( pState, "sourceResource" ); lua_pushelement ( pState, pSourceResource->GetResourceDynamicEntity() ); lua_setglobal ( pState, "sourceResourceRoot" ); } else { lua_pushnil ( pState ); lua_setglobal ( pState, "sourceResource" ); lua_pushnil ( pState ); lua_setglobal ( pState, "sourceResourceRoot" ); } lua_pushstring ( pState, szName ); lua_setglobal ( pState, "eventName" ); // Call it pMapEvent->Call ( Arguments ); bCalled = true; // Reset the globals on that VM OldSource.Push ( pState ); lua_setglobal ( pState, "source" ); OldThis.Push ( pState ); lua_setglobal ( pState, "this" ); OldResource.Push ( pState ); lua_setglobal ( pState, "sourceResource" ); OldResourceRoot.Push ( pState ); lua_setglobal ( pState, "sourceResourceRoot" ); OldEventName.Push ( pState ); lua_setglobal ( pState, "eventName" ); #if MTA_DEBUG assert ( lua_gettop ( pState ) == luaStackPointer ); #endif // Aspect ratio adjustment bodges if ( pMapEvent->ShouldAllowAspectRatioAdjustment() ) { g_pCore->GetGraphics()->SetAspectRatioAdjustmentEnabled( false ); g_bAllowAspectRatioAdjustment = false; } TIMEUS deltaTimeUs = GetTimeUs() - startTime; if ( deltaTimeUs > 3000 ) if ( IS_TIMING_CHECKPOINTS() ) strStatus += SString ( " (%s %d ms)", pMapEvent->GetVM ()->GetScriptName (), deltaTimeUs / 1000 ); CClientPerfStatLuaTiming::GetSingleton ()->UpdateLuaTiming ( pMapEvent->GetVM (), szName, deltaTimeUs ); } } } } // Clean out the trash if we're no longer calling events. if ( !bIsAlreadyIterating ) { TakeOutTheTrash (); // We're no longer iterating the list m_bIteratingList = false; } if ( IS_TIMING_CHECKPOINTS() ) { TIMEUS deltaTimeUs = GetTimeUs() - startTimeCall; if ( deltaTimeUs > 5000 ) TIMING_DETAIL( SString ( "CMapEventManager::Call ( %s, ... ) took %d ms ( %s )", szName, deltaTimeUs / 1000, *strStatus ) ); } // Return whether we called atleast one func or not return bCalled; }
bool CLuaArguments::Call ( CLuaMain* pLuaMain, const CLuaFunctionRef& iLuaFunction, CLuaArguments * returnValues ) const { assert ( pLuaMain ); TIMEUS startTime = GetTimeUs (); // Add the function name to the stack and get the event from the table lua_State* luaVM = pLuaMain->GetVirtualMachine (); assert ( luaVM ); LUA_CHECKSTACK ( luaVM, 1 ); int luaStackPointer = lua_gettop ( luaVM ); lua_getref ( luaVM, iLuaFunction.ToInt () ); // Push our arguments onto the stack PushArguments ( luaVM ); // Call the function with our arguments pLuaMain->ResetInstructionCount (); int iret = lua_pcall ( luaVM, m_Arguments.size (), LUA_MULTRET, 0 ); if ( iret == LUA_ERRRUN || iret == LUA_ERRMEM ) { SString strRes = ConformResourcePath ( lua_tostring( luaVM, -1 ) ); vector <SString> vecSplit; strRes.Split ( ":", vecSplit ); if ( vecSplit.size ( ) >= 3 ) { SString strFile = vecSplit[0]; int iLine = atoi ( vecSplit[1].c_str ( ) ); SString strMsg = vecSplit[2].substr ( 1 ); g_pGame->GetScriptDebugging()->LogError ( strFile, iLine, strMsg ); } else g_pGame->GetScriptDebugging()->LogError ( luaVM, "%s", strRes.c_str () ); // cleanup the stack while ( lua_gettop ( luaVM ) - luaStackPointer > 0 ) lua_pop ( luaVM, 1 ); return false; // the function call failed } else { int iReturns = lua_gettop ( luaVM ) - luaStackPointer; if ( returnValues != NULL ) { for ( int i = - iReturns; i <= -1; i++ ) { returnValues->ReadArgument ( luaVM, i ); } } // cleanup the stack while ( lua_gettop ( luaVM ) - luaStackPointer > 0 ) lua_pop ( luaVM, 1 ); } CPerfStatLuaTiming::GetSingleton ()->UpdateLuaTiming ( pLuaMain, pLuaMain->GetFunctionTag ( iLuaFunction.m_iFunction ), GetTimeUs() - startTime ); return true; }