2013-08-04 17:11:25 -04:00
// LuaState.cpp
// Implements the cLuaState class representing the wrapper over lua_State *, provides associated helper functions
# include "Globals.h"
# include "LuaState.h"
extern " C "
{
2013-11-26 12:14:46 -05:00
# include "lua/src/lualib.h"
2013-08-04 17:11:25 -04:00
}
2014-03-25 13:15:05 -04:00
# undef TOLUA_TEMPLATE_BIND
2013-12-08 12:24:56 -05:00
# include "tolua++/include/tolua++.h"
2013-08-04 17:11:25 -04:00
# include "Bindings.h"
# include "ManualBindings.h"
2014-03-02 04:12:29 -05:00
# include "DeprecatedBindings.h"
2015-12-23 05:08:39 -05:00
# include "LuaJson.h"
2014-10-19 05:46:38 -04:00
# include "../Entities/Entity.h"
# include "../BlockEntities/BlockEntity.h"
2013-08-04 17:11:25 -04:00
2016-03-02 05:34:39 -05:00
2015-05-09 03:25:09 -04:00
// fwd: "SQLite/lsqlite3.c"
2013-08-04 17:11:25 -04:00
extern " C "
{
2013-12-27 05:51:08 -05:00
int luaopen_lsqlite3 ( lua_State * L ) ;
2013-08-04 17:11:25 -04:00
}
2015-05-09 03:25:09 -04:00
// fwd: "LuaExpat/lxplib.c":
2013-08-04 17:11:25 -04:00
extern " C "
{
int luaopen_lxp ( lua_State * L ) ;
}
2013-08-15 07:05:24 -04:00
const cLuaState : : cRet cLuaState : : Return = { } ;
2013-08-08 08:08:21 -04:00
2016-03-02 05:34:39 -05:00
/** Each Lua state stores a pointer to its creating cLuaState in Lua globals, under this name.
This way any cLuaState can reference the main cLuaState ' s TrackedCallbacks , mutex etc . */
static const char * g_CanonLuaStateGlobalName = " _CuberiteInternal_CanonLuaState " ;
2013-08-08 08:08:21 -04:00
2015-09-28 15:30:31 -04:00
////////////////////////////////////////////////////////////////////////////////
// cLuaStateTracker:
void cLuaStateTracker : : Add ( cLuaState & a_LuaState )
{
auto & Instance = Get ( ) ;
cCSLock Lock ( Instance . m_CSLuaStates ) ;
Instance . m_LuaStates . push_back ( & a_LuaState ) ;
}
void cLuaStateTracker : : Del ( cLuaState & a_LuaState )
{
auto & Instance = Get ( ) ;
cCSLock Lock ( Instance . m_CSLuaStates ) ;
Instance . m_LuaStates . erase (
std : : remove_if (
Instance . m_LuaStates . begin ( ) , Instance . m_LuaStates . end ( ) ,
[ & a_LuaState ] ( cLuaStatePtr a_StoredLuaState )
{
return ( & a_LuaState = = a_StoredLuaState ) ;
}
) ,
Instance . m_LuaStates . end ( )
) ;
}
AString cLuaStateTracker : : GetStats ( void )
{
auto & Instance = Get ( ) ;
cCSLock Lock ( Instance . m_CSLuaStates ) ;
AString res ;
int Total = 0 ;
for ( auto state : Instance . m_LuaStates )
{
int Mem = 0 ;
if ( ! state - > Call ( " collectgarbage " , " count " , cLuaState : : Return , Mem ) )
{
res . append ( Printf ( " Cannot query memory for state \" %s \" \n " , state - > GetSubsystemName ( ) . c_str ( ) ) ) ;
}
else
{
res . append ( Printf ( " State \" %s \" is using %d KiB of memory \n " , state - > GetSubsystemName ( ) . c_str ( ) , Mem ) ) ;
Total + = Mem ;
}
}
res . append ( Printf ( " Total memory used by Lua: %d KiB \n " , Total ) ) ;
return res ;
}
cLuaStateTracker & cLuaStateTracker : : Get ( void )
{
static cLuaStateTracker Inst ; // The singleton
return Inst ;
}
2016-03-02 05:34:39 -05:00
////////////////////////////////////////////////////////////////////////////////
// cLuaState::cCallback:
2016-06-12 10:53:24 -04:00
cLuaState : : cCallback : : cCallback ( void ) :
m_CS ( nullptr )
{
}
2016-03-02 05:34:39 -05:00
bool cLuaState : : cCallback : : RefStack ( cLuaState & a_LuaState , int a_StackPos )
{
// Check if the stack contains a function:
if ( ! lua_isfunction ( a_LuaState , a_StackPos ) )
{
return false ;
}
// Clear any previous callback:
Clear ( ) ;
// Add self to LuaState's callback-tracking:
2016-06-12 10:53:24 -04:00
auto canonState = a_LuaState . QueryCanonLuaState ( ) ;
canonState - > TrackCallback ( * this ) ;
2016-03-02 05:34:39 -05:00
// Store the new callback:
2016-06-12 10:53:24 -04:00
m_CS = & ( canonState - > m_CS ) ;
m_Ref . RefStack ( * canonState , a_StackPos ) ;
2016-03-02 05:34:39 -05:00
return true ;
}
void cLuaState : : cCallback : : Clear ( void )
{
// Free the callback reference:
lua_State * luaState = nullptr ;
{
2016-06-12 10:53:24 -04:00
auto cs = m_CS ;
if ( cs ! = nullptr )
2016-03-02 05:34:39 -05:00
{
2016-06-12 10:53:24 -04:00
cCSLock Lock ( * cs ) ;
if ( ! m_Ref . IsValid ( ) )
{
return ;
}
luaState = m_Ref . GetLuaState ( ) ;
m_Ref . UnRef ( ) ;
2016-03-02 05:34:39 -05:00
}
}
// Remove from LuaState's callback-tracking:
2016-06-12 10:53:24 -04:00
if ( luaState = = nullptr )
{
return ;
}
2016-03-02 05:34:39 -05:00
cLuaState ( luaState ) . UntrackCallback ( * this ) ;
}
2016-03-02 04:12:43 -05:00
bool cLuaState : : cCallback : : IsValid ( void )
{
2016-06-12 10:53:24 -04:00
auto cs = m_CS ;
if ( cs = = nullptr )
{
return false ;
}
cCSLock lock ( * cs ) ;
2016-03-02 04:12:43 -05:00
return m_Ref . IsValid ( ) ;
}
2016-06-10 15:30:07 -04:00
bool cLuaState : : cCallback : : IsSameLuaState ( cLuaState & a_LuaState )
{
2016-06-12 10:53:24 -04:00
auto cs = m_CS ;
if ( cs = = nullptr )
{
return false ;
}
cCSLock lock ( * cs ) ;
2016-06-10 15:30:07 -04:00
if ( ! m_Ref . IsValid ( ) )
{
return false ;
}
auto canonState = a_LuaState . QueryCanonLuaState ( ) ;
if ( canonState = = nullptr )
{
return false ;
}
return ( m_Ref . GetLuaState ( ) = = static_cast < lua_State * > ( * canonState ) ) ;
}
2016-03-02 05:34:39 -05:00
void cLuaState : : cCallback : : Invalidate ( void )
{
2016-06-12 10:53:24 -04:00
auto cs = m_CS ;
if ( cs = = nullptr )
{
// Already invalid
return ;
}
cCSLock Lock ( * cs ) ;
2016-03-02 05:34:39 -05:00
if ( ! m_Ref . IsValid ( ) )
{
2016-06-12 10:53:24 -04:00
LOGD ( " %s: Inconsistent callback at %p, has a CS but an invalid Ref. This should not happen " ,
2016-03-02 05:34:39 -05:00
__FUNCTION__ , reinterpret_cast < void * > ( this )
) ;
return ;
}
m_Ref . UnRef ( ) ;
}
2014-07-17 16:15:34 -04:00
////////////////////////////////////////////////////////////////////////////////
2013-08-04 17:11:25 -04:00
// cLuaState:
cLuaState : : cLuaState ( const AString & a_SubsystemName ) :
2014-10-20 16:55:07 -04:00
m_LuaState ( nullptr ) ,
2013-08-06 02:01:00 -04:00
m_IsOwned ( false ) ,
2013-08-06 02:59:54 -04:00
m_SubsystemName ( a_SubsystemName ) ,
m_NumCurrentFunctionArgs ( - 1 )
2013-08-04 17:11:25 -04:00
{
}
2013-08-06 02:01:00 -04:00
cLuaState : : cLuaState ( lua_State * a_AttachState ) :
m_LuaState ( a_AttachState ) ,
m_IsOwned ( false ) ,
2013-08-06 02:59:54 -04:00
m_SubsystemName ( " <attached> " ) ,
m_NumCurrentFunctionArgs ( - 1 )
2013-08-06 02:01:00 -04:00
{
}
2013-08-04 17:11:25 -04:00
cLuaState : : ~ cLuaState ( )
{
if ( IsValid ( ) )
{
2013-08-07 08:26:18 -04:00
if ( m_IsOwned )
{
Close ( ) ;
}
else
{
Detach ( ) ;
}
2013-08-04 17:11:25 -04:00
}
}
void cLuaState : : Create ( void )
{
2014-10-20 16:55:07 -04:00
if ( m_LuaState ! = nullptr )
2013-08-04 17:11:25 -04:00
{
LOGWARNING ( " %s: Trying to create an already-existing LuaState, ignoring. " , __FUNCTION__ ) ;
return ;
}
m_LuaState = lua_open ( ) ;
luaL_openlibs ( m_LuaState ) ;
2014-03-12 08:05:28 -04:00
m_IsOwned = true ;
2015-09-28 15:30:31 -04:00
cLuaStateTracker : : Add ( * this ) ;
2016-03-02 05:34:39 -05:00
// Add the CanonLuaState value into the Lua state, so that we can get it from anywhere:
lua_pushlightuserdata ( m_LuaState , reinterpret_cast < void * > ( this ) ) ;
lua_setglobal ( m_LuaState , g_CanonLuaStateGlobalName ) ;
2014-03-12 08:05:28 -04:00
}
void cLuaState : : RegisterAPILibs ( void )
{
2013-08-04 17:11:25 -04:00
tolua_AllToLua_open ( m_LuaState ) ;
2015-05-13 05:30:57 -04:00
cManualBindings : : Bind ( m_LuaState ) ;
2014-03-02 04:12:29 -05:00
DeprecatedBindings : : Bind ( m_LuaState ) ;
2015-12-23 05:08:39 -05:00
cLuaJson : : Bind ( * this ) ;
2013-08-04 17:11:25 -04:00
luaopen_lsqlite3 ( m_LuaState ) ;
luaopen_lxp ( m_LuaState ) ;
}
void cLuaState : : Close ( void )
{
2014-10-20 16:55:07 -04:00
if ( m_LuaState = = nullptr )
2013-08-04 17:11:25 -04:00
{
LOGWARNING ( " %s: Trying to close an invalid LuaState, ignoring. " , __FUNCTION__ ) ;
return ;
}
2013-08-06 02:01:00 -04:00
if ( ! m_IsOwned )
{
LOGWARNING (
" %s: Detected mis-use, calling Close() on an attached state (0x%p). Detaching instead. " ,
2015-09-24 10:04:44 -04:00
__FUNCTION__ , static_cast < void * > ( m_LuaState )
2013-08-06 02:01:00 -04:00
) ;
Detach ( ) ;
return ;
}
2016-03-02 05:34:39 -05:00
// Invalidate all callbacks:
{
cCSLock Lock ( m_CSTrackedCallbacks ) ;
for ( auto & c : m_TrackedCallbacks )
{
c - > Invalidate ( ) ;
}
}
2015-09-28 15:30:31 -04:00
cLuaStateTracker : : Del ( * this ) ;
2013-08-04 17:11:25 -04:00
lua_close ( m_LuaState ) ;
2014-10-20 16:55:07 -04:00
m_LuaState = nullptr ;
2013-08-06 02:01:00 -04:00
m_IsOwned = false ;
}
void cLuaState : : Attach ( lua_State * a_State )
{
2014-10-20 16:55:07 -04:00
if ( m_LuaState ! = nullptr )
2013-08-06 02:01:00 -04:00
{
2015-09-24 10:04:44 -04:00
LOGINFO ( " %s: Already contains a LuaState (0x%p), will be closed / detached. " , __FUNCTION__ , static_cast < void * > ( m_LuaState ) ) ;
2013-08-06 02:01:00 -04:00
if ( m_IsOwned )
{
Close ( ) ;
}
else
{
Detach ( ) ;
}
}
m_LuaState = a_State ;
m_IsOwned = false ;
}
void cLuaState : : Detach ( void )
{
2014-10-20 16:55:07 -04:00
if ( m_LuaState = = nullptr )
2013-08-06 02:01:00 -04:00
{
return ;
}
if ( m_IsOwned )
{
LOGWARNING (
" %s: Detected a mis-use, calling Detach() when the state is owned. Closing the owned state (0x%p). " ,
2015-09-24 10:04:44 -04:00
__FUNCTION__ , static_cast < void * > ( m_LuaState )
2013-08-06 02:01:00 -04:00
) ;
Close ( ) ;
return ;
}
2014-10-20 16:55:07 -04:00
m_LuaState = nullptr ;
2013-08-04 17:11:25 -04:00
}
2014-02-17 17:12:46 -05:00
void cLuaState : : AddPackagePath ( const AString & a_PathVariable , const AString & a_Path )
{
// Get the current path:
lua_getfield ( m_LuaState , LUA_GLOBALSINDEX , " package " ) ; // Stk: <package>
lua_getfield ( m_LuaState , - 1 , a_PathVariable . c_str ( ) ) ; // Stk: <package> <package.path>
size_t len = 0 ;
const char * PackagePath = lua_tolstring ( m_LuaState , - 1 , & len ) ;
2016-02-05 16:45:45 -05:00
2014-02-17 17:12:46 -05:00
// Append the new path:
AString NewPackagePath ( PackagePath , len ) ;
NewPackagePath . append ( LUA_PATHSEP ) ;
NewPackagePath . append ( a_Path ) ;
2016-02-05 16:45:45 -05:00
2014-02-17 17:12:46 -05:00
// Set the new path to the environment:
lua_pop ( m_LuaState , 1 ) ; // Stk: <package>
lua_pushlstring ( m_LuaState , NewPackagePath . c_str ( ) , NewPackagePath . length ( ) ) ; // Stk: <package> <NewPackagePath>
lua_setfield ( m_LuaState , - 2 , a_PathVariable . c_str ( ) ) ; // Stk: <package>
lua_pop ( m_LuaState , 1 ) ;
lua_pop ( m_LuaState , 1 ) ; // Stk: -
}
2015-06-17 09:21:20 -04:00
bool cLuaState : : LoadFile ( const AString & a_FileName , bool a_LogWarnings )
2013-08-04 17:11:25 -04:00
{
ASSERT ( IsValid ( ) ) ;
2015-11-11 04:32:42 -05:00
2013-08-04 17:11:25 -04:00
// Load the file:
int s = luaL_loadfile ( m_LuaState , a_FileName . c_str ( ) ) ;
2015-06-17 09:21:20 -04:00
if ( s ! = 0 )
2013-08-04 17:11:25 -04:00
{
2015-06-17 09:21:20 -04:00
if ( a_LogWarnings )
{
LOGWARNING ( " Can't load %s because of a load error in file %s: %d (%s) " , m_SubsystemName . c_str ( ) , a_FileName . c_str ( ) , s , lua_tostring ( m_LuaState , - 1 ) ) ;
}
lua_pop ( m_LuaState , 1 ) ;
2013-08-04 17:11:25 -04:00
return false ;
}
// Execute the globals:
s = lua_pcall ( m_LuaState , 0 , LUA_MULTRET , 0 ) ;
2015-06-17 09:21:20 -04:00
if ( s ! = 0 )
2013-08-04 17:11:25 -04:00
{
2015-06-17 09:21:20 -04:00
if ( a_LogWarnings )
{
LOGWARNING ( " Can't load %s because of an initialization error in file %s: %d (%s) " , m_SubsystemName . c_str ( ) , a_FileName . c_str ( ) , s , lua_tostring ( m_LuaState , - 1 ) ) ;
}
lua_pop ( m_LuaState , 1 ) ;
2013-08-04 17:11:25 -04:00
return false ;
}
2015-11-11 04:32:42 -05:00
return true ;
}
bool cLuaState : : LoadString ( const AString & a_StringToLoad , const AString & a_FileName , bool a_LogWarnings )
{
ASSERT ( IsValid ( ) ) ;
// Load the file:
int s = luaL_loadstring ( m_LuaState , a_StringToLoad . c_str ( ) ) ;
if ( s ! = 0 )
{
if ( a_LogWarnings )
{
LOGWARNING ( " Can't load %s because of a load error in string from \" %s \" : %d (%s) " , m_SubsystemName . c_str ( ) , a_FileName . c_str ( ) , s , lua_tostring ( m_LuaState , - 1 ) ) ;
}
lua_pop ( m_LuaState , 1 ) ;
return false ;
}
// Execute the globals:
s = lua_pcall ( m_LuaState , 0 , LUA_MULTRET , 0 ) ;
if ( s ! = 0 )
{
if ( a_LogWarnings )
{
LOGWARNING ( " Can't load %s because of an initialization error in string from \" %s \" : %d (%s) " , m_SubsystemName . c_str ( ) , a_FileName . c_str ( ) , s , lua_tostring ( m_LuaState , - 1 ) ) ;
}
lua_pop ( m_LuaState , 1 ) ;
return false ;
}
2013-08-04 17:11:25 -04:00
return true ;
}
2013-08-08 10:02:07 -04:00
bool cLuaState : : HasFunction ( const char * a_FunctionName )
{
if ( ! IsValid ( ) )
{
// This happens if cPlugin::Initialize() fails with an error
return false ;
}
lua_getglobal ( m_LuaState , a_FunctionName ) ;
bool res = ( ! lua_isnil ( m_LuaState , - 1 ) & & lua_isfunction ( m_LuaState , - 1 ) ) ;
lua_pop ( m_LuaState , 1 ) ;
return res ;
}
bool cLuaState : : PushFunction ( const char * a_FunctionName )
2013-08-04 17:11:25 -04:00
{
2013-08-06 02:59:54 -04:00
ASSERT ( m_NumCurrentFunctionArgs = = - 1 ) ; // If not, there's already something pushed onto the stack
2013-08-04 17:11:25 -04:00
if ( ! IsValid ( ) )
{
// This happens if cPlugin::Initialize() fails with an error
return false ;
}
2016-02-05 16:45:45 -05:00
2014-01-11 17:10:40 -05:00
// Push the error handler for lua_pcall()
lua_pushcfunction ( m_LuaState , & ReportFnCallErrors ) ;
2016-02-05 16:45:45 -05:00
2013-08-04 17:11:25 -04:00
lua_getglobal ( m_LuaState , a_FunctionName ) ;
if ( ! lua_isfunction ( m_LuaState , - 1 ) )
{
2013-08-08 10:02:07 -04:00
LOGWARNING ( " Error in %s: Could not find function %s() " , m_SubsystemName . c_str ( ) , a_FunctionName ) ;
2014-01-21 16:59:08 -05:00
lua_pop ( m_LuaState , 2 ) ;
2013-08-04 17:11:25 -04:00
return false ;
}
2013-08-06 02:59:54 -04:00
m_CurrentFunctionName . assign ( a_FunctionName ) ;
m_NumCurrentFunctionArgs = 0 ;
2013-08-04 17:11:25 -04:00
return true ;
}
2016-06-12 12:24:01 -04:00
bool cLuaState : : PushFunction ( const cRef & a_FnRef )
2013-08-04 17:11:25 -04:00
{
2013-08-06 02:59:54 -04:00
ASSERT ( IsValid ( ) ) ;
ASSERT ( m_NumCurrentFunctionArgs = = - 1 ) ; // If not, there's already something pushed onto the stack
2016-02-05 16:45:45 -05:00
2014-01-11 17:10:40 -05:00
// Push the error handler for lua_pcall()
lua_pushcfunction ( m_LuaState , & ReportFnCallErrors ) ;
2016-02-05 16:45:45 -05:00
2016-06-12 12:24:01 -04:00
lua_rawgeti ( m_LuaState , LUA_REGISTRYINDEX , static_cast < int > ( a_FnRef ) ) ; // same as lua_getref()
2013-08-04 17:11:25 -04:00
if ( ! lua_isfunction ( m_LuaState , - 1 ) )
{
2014-01-21 16:59:08 -05:00
lua_pop ( m_LuaState , 2 ) ;
2013-08-04 17:11:25 -04:00
return false ;
}
2013-08-06 02:59:54 -04:00
m_CurrentFunctionName = " <callback> " ;
m_NumCurrentFunctionArgs = 0 ;
2013-08-04 17:11:25 -04:00
return true ;
}
2014-01-11 16:51:10 -05:00
bool cLuaState : : PushFunction ( const cTableRef & a_TableRef )
2013-08-07 08:26:18 -04:00
{
ASSERT ( IsValid ( ) ) ;
ASSERT ( m_NumCurrentFunctionArgs = = - 1 ) ; // If not, there's already something pushed onto the stack
2016-02-05 16:45:45 -05:00
2014-01-11 17:10:40 -05:00
// Push the error handler for lua_pcall()
lua_pushcfunction ( m_LuaState , & ReportFnCallErrors ) ;
2016-02-05 16:45:45 -05:00
2014-01-11 16:51:10 -05:00
lua_rawgeti ( m_LuaState , LUA_REGISTRYINDEX , a_TableRef . GetTableRef ( ) ) ; // Get the table ref
2013-08-07 08:26:18 -04:00
if ( ! lua_istable ( m_LuaState , - 1 ) )
{
// Not a table, bail out
2014-01-21 16:59:08 -05:00
lua_pop ( m_LuaState , 2 ) ;
2013-08-07 08:26:18 -04:00
return false ;
}
2014-01-11 16:51:10 -05:00
lua_getfield ( m_LuaState , - 1 , a_TableRef . GetFnName ( ) ) ;
2013-08-07 08:26:18 -04:00
if ( lua_isnil ( m_LuaState , - 1 ) | | ! lua_isfunction ( m_LuaState , - 1 ) )
{
// Not a valid function, bail out
2014-01-29 16:56:23 -05:00
lua_pop ( m_LuaState , 3 ) ;
2013-08-07 08:26:18 -04:00
return false ;
}
2016-02-05 16:45:45 -05:00
2014-01-29 16:56:23 -05:00
// Pop the table off the stack:
lua_remove ( m_LuaState , - 2 ) ;
2016-02-05 16:45:45 -05:00
2014-01-11 16:51:10 -05:00
Printf ( m_CurrentFunctionName , " <table-callback %s> " , a_TableRef . GetFnName ( ) ) ;
2013-08-07 08:26:18 -04:00
m_NumCurrentFunctionArgs = 0 ;
return true ;
}
2015-02-12 14:05:55 -05:00
void cLuaState : : PushNil ( void )
{
ASSERT ( IsValid ( ) ) ;
lua_pushnil ( m_LuaState ) ;
m_NumCurrentFunctionArgs + = 1 ;
}
2013-08-08 08:08:21 -04:00
void cLuaState : : Push ( const AString & a_String )
{
ASSERT ( IsValid ( ) ) ;
2014-01-07 09:55:23 -05:00
lua_pushlstring ( m_LuaState , a_String . data ( ) , a_String . size ( ) ) ;
2013-08-08 08:08:21 -04:00
m_NumCurrentFunctionArgs + = 1 ;
}
void cLuaState : : Push ( const AStringVector & a_Vector )
2013-08-04 17:11:25 -04:00
{
2013-08-06 02:59:54 -04:00
ASSERT ( IsValid ( ) ) ;
2015-07-29 11:04:03 -04:00
lua_createtable ( m_LuaState , static_cast < int > ( a_Vector . size ( ) ) , 0 ) ;
2013-08-04 17:11:25 -04:00
int newTable = lua_gettop ( m_LuaState ) ;
int index = 1 ;
for ( AStringVector : : const_iterator itr = a_Vector . begin ( ) , end = a_Vector . end ( ) ; itr ! = end ; + + itr , + + index )
{
tolua_pushstring ( m_LuaState , itr - > c_str ( ) ) ;
lua_rawseti ( m_LuaState , newTable , index ) ;
}
2013-08-06 02:59:54 -04:00
m_NumCurrentFunctionArgs + = 1 ;
}
2014-06-03 13:29:04 -04:00
void cLuaState : : Push ( const cCraftingGrid * a_Grid )
2013-08-06 02:59:54 -04:00
{
ASSERT ( IsValid ( ) ) ;
2015-07-29 11:04:03 -04:00
tolua_pushusertype ( m_LuaState , reinterpret_cast < void * > ( const_cast < cCraftingGrid * > ( a_Grid ) ) , " cCraftingGrid " ) ;
2013-08-06 02:59:54 -04:00
m_NumCurrentFunctionArgs + = 1 ;
}
2014-06-03 13:29:04 -04:00
void cLuaState : : Push ( const cCraftingRecipe * a_Recipe )
2013-08-06 02:59:54 -04:00
{
ASSERT ( IsValid ( ) ) ;
2015-07-29 11:04:03 -04:00
tolua_pushusertype ( m_LuaState , reinterpret_cast < void * > ( const_cast < cCraftingRecipe * > ( a_Recipe ) ) , " cCraftingRecipe " ) ;
2013-08-06 02:59:54 -04:00
m_NumCurrentFunctionArgs + = 1 ;
}
2014-06-03 13:29:04 -04:00
void cLuaState : : Push ( const char * a_Value )
2013-08-06 02:59:54 -04:00
{
ASSERT ( IsValid ( ) ) ;
2014-06-03 13:29:04 -04:00
tolua_pushstring ( m_LuaState , a_Value ) ;
2013-08-06 02:59:54 -04:00
m_NumCurrentFunctionArgs + = 1 ;
}
2014-06-03 13:29:04 -04:00
void cLuaState : : Push ( const cItems & a_Items )
2013-08-06 02:59:54 -04:00
{
ASSERT ( IsValid ( ) ) ;
2015-07-29 11:04:03 -04:00
tolua_pushusertype ( m_LuaState , reinterpret_cast < void * > ( const_cast < cItems * > ( & a_Items ) ) , " cItems " ) ;
2013-08-06 02:59:54 -04:00
m_NumCurrentFunctionArgs + = 1 ;
}
2014-06-03 13:29:04 -04:00
void cLuaState : : Push ( const cPlayer * a_Player )
2013-08-06 02:59:54 -04:00
{
ASSERT ( IsValid ( ) ) ;
2015-07-29 11:04:03 -04:00
tolua_pushusertype ( m_LuaState , reinterpret_cast < void * > ( const_cast < cPlayer * > ( a_Player ) ) , " cPlayer " ) ;
2013-08-06 02:59:54 -04:00
m_NumCurrentFunctionArgs + = 1 ;
}
2015-06-17 09:21:20 -04:00
void cLuaState : : Push ( const cLuaState : : cRef & a_Ref )
{
ASSERT ( IsValid ( ) ) ;
lua_rawgeti ( m_LuaState , LUA_REGISTRYINDEX , static_cast < int > ( a_Ref ) ) ;
m_NumCurrentFunctionArgs + = 1 ;
}
2014-06-03 13:29:04 -04:00
void cLuaState : : Push ( const HTTPRequest * a_Request )
2013-08-06 02:59:54 -04:00
{
ASSERT ( IsValid ( ) ) ;
2015-07-29 11:04:03 -04:00
tolua_pushusertype ( m_LuaState , reinterpret_cast < void * > ( const_cast < HTTPRequest * > ( a_Request ) ) , " HTTPRequest " ) ;
2013-08-06 02:59:54 -04:00
m_NumCurrentFunctionArgs + = 1 ;
}
2014-06-03 13:29:04 -04:00
void cLuaState : : Push ( const HTTPTemplateRequest * a_Request )
2013-08-06 02:59:54 -04:00
{
ASSERT ( IsValid ( ) ) ;
2015-07-29 11:04:03 -04:00
tolua_pushusertype ( m_LuaState , reinterpret_cast < void * > ( const_cast < HTTPTemplateRequest * > ( a_Request ) ) , " HTTPTemplateRequest " ) ;
2013-08-06 02:59:54 -04:00
m_NumCurrentFunctionArgs + = 1 ;
}
2014-06-03 13:29:04 -04:00
void cLuaState : : Push ( const Vector3d & a_Vector )
2013-08-08 08:08:21 -04:00
{
ASSERT ( IsValid ( ) ) ;
2015-07-29 11:04:03 -04:00
tolua_pushusertype ( m_LuaState , reinterpret_cast < void * > ( const_cast < Vector3d * > ( & a_Vector ) ) , " Vector3<double> " ) ;
2014-08-22 04:33:15 -04:00
m_NumCurrentFunctionArgs + = 1 ;
}
void cLuaState : : Push ( const Vector3d * a_Vector )
{
ASSERT ( IsValid ( ) ) ;
2015-07-29 11:04:03 -04:00
tolua_pushusertype ( m_LuaState , reinterpret_cast < void * > ( const_cast < Vector3d * > ( a_Vector ) ) , " Vector3<double> " ) ;
2014-08-22 04:33:15 -04:00
m_NumCurrentFunctionArgs + = 1 ;
}
void cLuaState : : Push ( const Vector3i & a_Vector )
{
ASSERT ( IsValid ( ) ) ;
2015-07-29 11:04:03 -04:00
tolua_pushusertype ( m_LuaState , reinterpret_cast < void * > ( const_cast < Vector3i * > ( & a_Vector ) ) , " Vector3<int> " ) ;
2014-08-22 04:33:15 -04:00
m_NumCurrentFunctionArgs + = 1 ;
}
void cLuaState : : Push ( const Vector3i * a_Vector )
{
ASSERT ( IsValid ( ) ) ;
2015-07-29 11:04:03 -04:00
tolua_pushusertype ( m_LuaState , reinterpret_cast < void * > ( const_cast < Vector3i * > ( a_Vector ) ) , " Vector3<int> " ) ;
2013-08-08 08:08:21 -04:00
m_NumCurrentFunctionArgs + = 1 ;
}
2014-06-03 13:29:04 -04:00
void cLuaState : : Push ( bool a_Value )
2013-08-06 02:59:54 -04:00
{
ASSERT ( IsValid ( ) ) ;
2014-06-03 13:29:04 -04:00
tolua_pushboolean ( m_LuaState , a_Value ? 1 : 0 ) ;
2013-08-06 02:59:54 -04:00
m_NumCurrentFunctionArgs + = 1 ;
}
2014-06-03 13:29:04 -04:00
void cLuaState : : Push ( cEntity * a_Entity )
{
ASSERT ( IsValid ( ) ) ;
2014-10-20 11:32:09 -04:00
if ( a_Entity = = nullptr )
{
lua_pushnil ( m_LuaState ) ;
}
2014-10-19 06:49:54 -04:00
else
{
2014-10-21 06:43:06 -04:00
switch ( a_Entity - > GetEntityType ( ) )
{
case cEntity : : etMonster :
{
// Don't push specific mob types, as those are not exported in the API:
tolua_pushusertype ( m_LuaState , a_Entity , " cMonster " ) ;
break ;
}
case cEntity : : etPlayer :
{
tolua_pushusertype ( m_LuaState , a_Entity , " cPlayer " ) ;
break ;
}
case cEntity : : etPickup :
{
tolua_pushusertype ( m_LuaState , a_Entity , " cPickup " ) ;
break ;
}
case cEntity : : etTNT :
{
tolua_pushusertype ( m_LuaState , a_Entity , " cTNTEntity " ) ;
break ;
}
case cEntity : : etProjectile :
{
2014-10-22 10:06:16 -04:00
tolua_pushusertype ( m_LuaState , a_Entity , a_Entity - > GetClass ( ) ) ;
2014-10-21 06:43:06 -04:00
break ;
}
case cEntity : : etFloater :
{
tolua_pushusertype ( m_LuaState , a_Entity , " cFloater " ) ;
break ;
}
case cEntity : : etEntity :
case cEntity : : etEnderCrystal :
case cEntity : : etFallingBlock :
case cEntity : : etMinecart :
case cEntity : : etBoat :
case cEntity : : etExpOrb :
case cEntity : : etItemFrame :
case cEntity : : etPainting :
{
// Push the generic entity class type:
tolua_pushusertype ( m_LuaState , a_Entity , " cEntity " ) ;
}
} // switch (EntityType)
2014-10-19 06:49:54 -04:00
}
2014-10-21 06:43:06 -04:00
2014-06-03 13:29:04 -04:00
m_NumCurrentFunctionArgs + = 1 ;
}
2015-01-30 15:24:02 -05:00
void cLuaState : : Push ( cLuaServerHandle * a_ServerHandle )
{
ASSERT ( IsValid ( ) ) ;
tolua_pushusertype ( m_LuaState , a_ServerHandle , " cServerHandle " ) ;
m_NumCurrentFunctionArgs + = 1 ;
}
2015-01-28 09:14:05 -05:00
void cLuaState : : Push ( cLuaTCPLink * a_TCPLink )
{
ASSERT ( IsValid ( ) ) ;
tolua_pushusertype ( m_LuaState , a_TCPLink , " cTCPLink " ) ;
m_NumCurrentFunctionArgs + = 1 ;
}
2015-02-20 08:28:05 -05:00
void cLuaState : : Push ( cLuaUDPEndpoint * a_UDPEndpoint )
{
ASSERT ( IsValid ( ) ) ;
tolua_pushusertype ( m_LuaState , a_UDPEndpoint , " cUDPEndpoint " ) ;
m_NumCurrentFunctionArgs + = 1 ;
}
2014-06-03 13:29:04 -04:00
void cLuaState : : Push ( double a_Value )
2013-08-08 10:02:07 -04:00
{
ASSERT ( IsValid ( ) ) ;
2014-06-03 13:29:04 -04:00
tolua_pushnumber ( m_LuaState , a_Value ) ;
2013-08-08 10:02:07 -04:00
m_NumCurrentFunctionArgs + = 1 ;
}
2014-06-03 13:29:04 -04:00
void cLuaState : : Push ( int a_Value )
2013-08-08 10:30:02 -04:00
{
ASSERT ( IsValid ( ) ) ;
2014-06-03 13:29:04 -04:00
tolua_pushnumber ( m_LuaState , a_Value ) ;
2013-08-08 10:30:02 -04:00
m_NumCurrentFunctionArgs + = 1 ;
}
2015-09-26 16:54:18 -04:00
void cLuaState : : Push ( long a_Value )
{
ASSERT ( IsValid ( ) ) ;
tolua_pushnumber ( m_LuaState , static_cast < lua_Number > ( a_Value ) ) ;
m_NumCurrentFunctionArgs + = 1 ;
}
2015-07-29 11:04:03 -04:00
void cLuaState : : Push ( UInt32 a_Value )
{
ASSERT ( IsValid ( ) ) ;
tolua_pushnumber ( m_LuaState , a_Value ) ;
m_NumCurrentFunctionArgs + = 1 ;
}
2015-01-11 16:12:26 -05:00
void cLuaState : : Push ( std : : chrono : : milliseconds a_Value )
{
ASSERT ( IsValid ( ) ) ;
2015-01-18 05:02:17 -05:00
tolua_pushnumber ( m_LuaState , static_cast < lua_Number > ( a_Value . count ( ) ) ) ;
2015-01-11 16:12:26 -05:00
m_NumCurrentFunctionArgs + = 1 ;
}
Added OnExploding() and OnExploded() hooks.
As requested in FS 413, with extra parameters:
World, BlockX, BlockY, BlockZ, Size, CanCauseFire, Source, SourceData
OnExploding() can return 3 values:
StopHook, CanCauseFire, ExplosionSize
2013-08-09 08:58:43 -04:00
2013-08-11 08:57:07 -04:00
2016-06-10 15:30:07 -04:00
void cLuaState : : Pop ( int a_NumValuesToPop )
{
ASSERT ( IsValid ( ) ) ;
lua_pop ( m_LuaState , a_NumValuesToPop ) ;
m_NumCurrentFunctionArgs - = a_NumValuesToPop ;
}
2015-05-19 10:25:18 -04:00
bool cLuaState : : GetStackValue ( int a_StackPos , AString & a_Value )
2015-04-23 13:41:01 -04:00
{
size_t len = 0 ;
const char * data = lua_tolstring ( m_LuaState , a_StackPos , & len ) ;
if ( data ! = nullptr )
{
a_Value . assign ( data , len ) ;
2015-05-19 10:25:18 -04:00
return true ;
2015-04-23 13:41:01 -04:00
}
2015-05-19 10:25:18 -04:00
return false ;
2015-04-23 13:41:01 -04:00
}
2015-05-19 10:25:18 -04:00
bool cLuaState : : GetStackValue ( int a_StackPos , bool & a_ReturnedVal )
2013-08-08 08:08:21 -04:00
{
a_ReturnedVal = ( tolua_toboolean ( m_LuaState , a_StackPos , a_ReturnedVal ? 1 : 0 ) > 0 ) ;
2015-05-19 10:25:18 -04:00
return true ;
2013-08-08 08:08:21 -04:00
}
2016-03-02 04:12:43 -05:00
bool cLuaState : : GetStackValue ( int a_StackPos , cCallback & a_Callback )
{
return a_Callback . RefStack ( * this , a_StackPos ) ;
}
bool cLuaState : : GetStackValue ( int a_StackPos , cCallbackPtr & a_Callback )
2016-06-27 14:49:59 -04:00
{
if ( a_Callback = = nullptr )
{
a_Callback = cpp14 : : make_unique < cCallback > ( ) ;
}
return a_Callback - > RefStack ( * this , a_StackPos ) ;
}
bool cLuaState : : GetStackValue ( int a_StackPos , cCallbackSharedPtr & a_Callback )
2016-03-02 04:12:43 -05:00
{
2016-06-12 12:11:40 -04:00
if ( a_Callback = = nullptr )
{
a_Callback = std : : make_shared < cCallback > ( ) ;
}
2016-03-02 04:12:43 -05:00
return a_Callback - > RefStack ( * this , a_StackPos ) ;
}
2015-05-19 10:25:18 -04:00
bool cLuaState : : GetStackValue ( int a_StackPos , cPluginManager : : CommandResult & a_Result )
2015-05-10 17:11:30 -04:00
{
if ( lua_isnumber ( m_LuaState , a_StackPos ) )
{
a_Result = static_cast < cPluginManager : : CommandResult > ( static_cast < int > ( ( tolua_tonumber ( m_LuaState , a_StackPos , a_Result ) ) ) ) ;
2015-05-19 10:25:18 -04:00
return true ;
2015-05-10 17:11:30 -04:00
}
2015-05-19 10:25:18 -04:00
return false ;
2015-05-10 17:11:30 -04:00
}
2015-05-19 10:25:18 -04:00
bool cLuaState : : GetStackValue ( int a_StackPos , cRef & a_Ref )
2013-08-08 08:08:21 -04:00
{
2015-04-23 13:41:01 -04:00
a_Ref . RefStack ( * this , a_StackPos ) ;
2015-05-19 10:25:18 -04:00
return true ;
2013-08-08 08:08:21 -04:00
}
2015-05-19 10:25:18 -04:00
bool cLuaState : : GetStackValue ( int a_StackPos , double & a_ReturnedVal )
2013-08-08 08:08:21 -04:00
{
if ( lua_isnumber ( m_LuaState , a_StackPos ) )
{
2015-04-23 13:41:01 -04:00
a_ReturnedVal = tolua_tonumber ( m_LuaState , a_StackPos , a_ReturnedVal ) ;
2015-05-19 10:25:18 -04:00
return true ;
Added OnExploding() and OnExploded() hooks.
As requested in FS 413, with extra parameters:
World, BlockX, BlockY, BlockZ, Size, CanCauseFire, Source, SourceData
OnExploding() can return 3 values:
StopHook, CanCauseFire, ExplosionSize
2013-08-09 08:58:43 -04:00
}
2015-05-19 10:25:18 -04:00
return false ;
Added OnExploding() and OnExploded() hooks.
As requested in FS 413, with extra parameters:
World, BlockX, BlockY, BlockZ, Size, CanCauseFire, Source, SourceData
OnExploding() can return 3 values:
StopHook, CanCauseFire, ExplosionSize
2013-08-09 08:58:43 -04:00
}
2015-06-17 09:21:20 -04:00
bool cLuaState : : GetStackValue ( int a_StackPos , eBlockFace & a_ReturnedVal )
2015-05-08 18:32:02 -04:00
{
2015-06-17 09:21:20 -04:00
if ( ! lua_isnumber ( m_LuaState , a_StackPos ) )
2015-05-08 18:32:02 -04:00
{
2015-06-17 09:21:20 -04:00
return false ;
2015-05-08 18:32:02 -04:00
}
2015-06-17 09:21:20 -04:00
a_ReturnedVal = static_cast < eBlockFace > ( Clamp (
static_cast < int > ( tolua_tonumber ( m_LuaState , a_StackPos , a_ReturnedVal ) ) ,
static_cast < int > ( BLOCK_FACE_MIN ) , static_cast < int > ( BLOCK_FACE_MAX ) )
) ;
return true ;
2015-05-08 18:32:02 -04:00
}
2015-05-19 10:25:18 -04:00
bool cLuaState : : GetStackValue ( int a_StackPos , eWeather & a_ReturnedVal )
Added OnExploding() and OnExploded() hooks.
As requested in FS 413, with extra parameters:
World, BlockX, BlockY, BlockZ, Size, CanCauseFire, Source, SourceData
OnExploding() can return 3 values:
StopHook, CanCauseFire, ExplosionSize
2013-08-09 08:58:43 -04:00
{
2015-04-23 13:41:01 -04:00
if ( ! lua_isnumber ( m_LuaState , a_StackPos ) )
Added OnExploding() and OnExploded() hooks.
As requested in FS 413, with extra parameters:
World, BlockX, BlockY, BlockZ, Size, CanCauseFire, Source, SourceData
OnExploding() can return 3 values:
StopHook, CanCauseFire, ExplosionSize
2013-08-09 08:58:43 -04:00
{
2015-05-19 10:25:18 -04:00
return false ;
2013-08-08 08:08:21 -04:00
}
2015-04-23 13:41:01 -04:00
a_ReturnedVal = static_cast < eWeather > ( Clamp (
static_cast < int > ( tolua_tonumber ( m_LuaState , a_StackPos , a_ReturnedVal ) ) ,
static_cast < int > ( wSunny ) , static_cast < int > ( wThunderstorm ) )
) ;
2015-05-19 10:25:18 -04:00
return true ;
2014-07-03 11:49:21 -04:00
}
2015-06-17 09:21:20 -04:00
bool cLuaState : : GetStackValue ( int a_StackPos , float & a_ReturnedVal )
{
if ( lua_isnumber ( m_LuaState , a_StackPos ) )
{
a_ReturnedVal = static_cast < float > ( tolua_tonumber ( m_LuaState , a_StackPos , a_ReturnedVal ) ) ;
return true ;
}
return false ;
}
cLuaState : : cStackValue cLuaState : : WalkToValue ( const AString & a_Name )
{
2015-06-20 09:37:41 -04:00
// There needs to be at least one value on the stack:
ASSERT ( lua_gettop ( m_LuaState ) > 0 ) ;
// Iterate over path and replace the top of the stack with the walked element
2015-06-17 09:21:20 -04:00
lua_pushvalue ( m_LuaState , - 1 ) ; // Copy the stack value into the "working area"
2015-06-20 09:37:41 -04:00
auto path = StringSplit ( a_Name , " . " ) ;
2015-06-17 09:21:20 -04:00
for ( const auto & elem : path )
{
// If the value is not a table, bail out (error):
if ( ! lua_istable ( m_LuaState , - 1 ) )
{
lua_pop ( m_LuaState , 1 ) ;
return cStackValue ( ) ;
}
// Get the next part of the path:
lua_getfield ( m_LuaState , - 1 , elem . c_str ( ) ) ;
// Remove the previous value from the stack (keep only the new one):
lua_remove ( m_LuaState , - 2 ) ;
} // for elem - path[]
2015-11-11 04:32:42 -05:00
if ( lua_isnil ( m_LuaState , - 1 ) )
{
lua_pop ( m_LuaState , 1 ) ;
return cStackValue ( ) ;
}
2015-07-21 18:40:13 -04:00
return cStackValue ( * this ) ;
2015-06-17 09:21:20 -04:00
}
2015-11-11 04:32:42 -05:00
cLuaState : : cStackValue cLuaState : : WalkToNamedGlobal ( const AString & a_Name )
{
// Iterate over path and replace the top of the stack with the walked element
lua_getglobal ( m_LuaState , " _G " ) ;
auto path = StringSplit ( a_Name , " . " ) ;
for ( const auto & elem : path )
{
// If the value is not a table, bail out (error):
if ( ! lua_istable ( m_LuaState , - 1 ) )
{
lua_pop ( m_LuaState , 1 ) ;
return cStackValue ( ) ;
}
// Get the next part of the path:
lua_getfield ( m_LuaState , - 1 , elem . c_str ( ) ) ;
// Remove the previous value from the stack (keep only the new one):
lua_remove ( m_LuaState , - 2 ) ;
} // for elem - path[]
if ( lua_isnil ( m_LuaState , - 1 ) )
{
lua_pop ( m_LuaState , 1 ) ;
return cStackValue ( ) ;
}
2015-12-19 16:41:17 -05:00
return cStackValue ( * this ) ;
2015-11-11 04:32:42 -05:00
}
2013-08-06 02:59:54 -04:00
bool cLuaState : : CallFunction ( int a_NumResults )
2013-08-04 17:11:25 -04:00
{
2013-08-06 02:59:54 -04:00
ASSERT ( m_NumCurrentFunctionArgs > = 0 ) ; // A function must be pushed to stack first
2014-01-11 17:10:40 -05:00
ASSERT ( lua_isfunction ( m_LuaState , - m_NumCurrentFunctionArgs - 1 ) ) ; // The function to call
ASSERT ( lua_isfunction ( m_LuaState , - m_NumCurrentFunctionArgs - 2 ) ) ; // The error handler
2016-02-05 16:45:45 -05:00
2014-02-11 02:52:14 -05:00
// Save the current "stack" state and reset, in case the callback calls another function:
AString CurrentFunctionName ;
std : : swap ( m_CurrentFunctionName , CurrentFunctionName ) ;
int NumArgs = m_NumCurrentFunctionArgs ;
m_NumCurrentFunctionArgs = - 1 ;
2016-02-05 16:45:45 -05:00
2014-02-11 02:52:14 -05:00
// Call the function:
int s = lua_pcall ( m_LuaState , NumArgs , a_NumResults , - NumArgs - 2 ) ;
2014-01-11 17:10:40 -05:00
if ( s ! = 0 )
2013-08-04 17:11:25 -04:00
{
2014-01-11 17:10:40 -05:00
// The error has already been printed together with the stacktrace
2014-02-11 02:52:14 -05:00
LOGWARNING ( " Error in %s calling function %s() " , m_SubsystemName . c_str ( ) , CurrentFunctionName . c_str ( ) ) ;
2013-08-04 17:11:25 -04:00
return false ;
}
2016-02-05 16:45:45 -05:00
2014-01-21 16:59:08 -05:00
// Remove the error handler from the stack:
lua_remove ( m_LuaState , - a_NumResults - 1 ) ;
2016-02-05 16:45:45 -05:00
2013-08-04 17:11:25 -04:00
return true ;
}
2013-11-22 10:49:38 -05:00
bool cLuaState : : CheckParamUserTable ( int a_StartParam , const char * a_UserTable , int a_EndParam )
{
ASSERT ( IsValid ( ) ) ;
2016-02-05 16:45:45 -05:00
2013-11-22 10:49:38 -05:00
if ( a_EndParam < 0 )
{
a_EndParam = a_StartParam ;
}
2016-02-05 16:45:45 -05:00
2013-11-22 10:49:38 -05:00
tolua_Error tolua_err ;
for ( int i = a_StartParam ; i < = a_EndParam ; i + + )
{
if ( tolua_isusertable ( m_LuaState , i , a_UserTable , 0 , & tolua_err ) )
{
continue ;
}
// Not the correct parameter
lua_Debug entry ;
VERIFY ( lua_getstack ( m_LuaState , 0 , & entry ) ) ;
VERIFY ( lua_getinfo ( m_LuaState , " n " , & entry ) ) ;
2014-10-20 16:55:07 -04:00
AString ErrMsg = Printf ( " #ferror in function '%s'. " , ( entry . name ! = nullptr ) ? entry . name : " ? " ) ;
2013-11-22 10:49:38 -05:00
tolua_error ( m_LuaState , ErrMsg . c_str ( ) , & tolua_err ) ;
return false ;
} // for i - Param
2016-02-05 16:45:45 -05:00
2013-11-22 10:49:38 -05:00
// All params checked ok
return true ;
}
2013-08-07 08:26:18 -04:00
bool cLuaState : : CheckParamUserType ( int a_StartParam , const char * a_UserType , int a_EndParam )
{
ASSERT ( IsValid ( ) ) ;
2016-02-05 16:45:45 -05:00
2013-08-07 08:26:18 -04:00
if ( a_EndParam < 0 )
{
a_EndParam = a_StartParam ;
}
2016-02-05 16:45:45 -05:00
2013-08-07 08:26:18 -04:00
tolua_Error tolua_err ;
for ( int i = a_StartParam ; i < = a_EndParam ; i + + )
{
if ( tolua_isusertype ( m_LuaState , i , a_UserType , 0 , & tolua_err ) )
{
continue ;
}
// Not the correct parameter
lua_Debug entry ;
VERIFY ( lua_getstack ( m_LuaState , 0 , & entry ) ) ;
VERIFY ( lua_getinfo ( m_LuaState , " n " , & entry ) ) ;
2014-10-20 16:55:07 -04:00
AString ErrMsg = Printf ( " #ferror in function '%s'. " , ( entry . name ! = nullptr ) ? entry . name : " ? " ) ;
2013-08-07 08:26:18 -04:00
tolua_error ( m_LuaState , ErrMsg . c_str ( ) , & tolua_err ) ;
return false ;
} // for i - Param
2016-02-05 16:45:45 -05:00
2013-08-07 08:26:18 -04:00
// All params checked ok
return true ;
}
bool cLuaState : : CheckParamTable ( int a_StartParam , int a_EndParam )
{
ASSERT ( IsValid ( ) ) ;
2016-02-05 16:45:45 -05:00
2013-08-07 08:26:18 -04:00
if ( a_EndParam < 0 )
{
a_EndParam = a_StartParam ;
}
2016-02-05 16:45:45 -05:00
2013-08-07 08:26:18 -04:00
tolua_Error tolua_err ;
for ( int i = a_StartParam ; i < = a_EndParam ; i + + )
{
if ( tolua_istable ( m_LuaState , i , 0 , & tolua_err ) )
{
continue ;
}
// Not the correct parameter
lua_Debug entry ;
VERIFY ( lua_getstack ( m_LuaState , 0 , & entry ) ) ;
VERIFY ( lua_getinfo ( m_LuaState , " n " , & entry ) ) ;
2014-10-20 16:55:07 -04:00
AString ErrMsg = Printf ( " #ferror in function '%s'. " , ( entry . name ! = nullptr ) ? entry . name : " ? " ) ;
2015-05-16 10:19:18 -04:00
BreakIntoDebugger ( m_LuaState ) ;
2013-08-07 08:26:18 -04:00
tolua_error ( m_LuaState , ErrMsg . c_str ( ) , & tolua_err ) ;
return false ;
} // for i - Param
2016-02-05 16:45:45 -05:00
2013-08-07 08:26:18 -04:00
// All params checked ok
return true ;
}
bool cLuaState : : CheckParamNumber ( int a_StartParam , int a_EndParam )
{
ASSERT ( IsValid ( ) ) ;
2016-02-05 16:45:45 -05:00
2013-08-07 08:26:18 -04:00
if ( a_EndParam < 0 )
{
a_EndParam = a_StartParam ;
}
2016-02-05 16:45:45 -05:00
2013-08-07 08:26:18 -04:00
tolua_Error tolua_err ;
for ( int i = a_StartParam ; i < = a_EndParam ; i + + )
{
if ( tolua_isnumber ( m_LuaState , i , 0 , & tolua_err ) )
{
continue ;
}
// Not the correct parameter
lua_Debug entry ;
VERIFY ( lua_getstack ( m_LuaState , 0 , & entry ) ) ;
VERIFY ( lua_getinfo ( m_LuaState , " n " , & entry ) ) ;
2014-10-20 16:55:07 -04:00
AString ErrMsg = Printf ( " #ferror in function '%s'. " , ( entry . name ! = nullptr ) ? entry . name : " ? " ) ;
2013-08-07 08:26:18 -04:00
tolua_error ( m_LuaState , ErrMsg . c_str ( ) , & tolua_err ) ;
return false ;
} // for i - Param
2016-02-05 16:45:45 -05:00
2013-08-07 08:26:18 -04:00
// All params checked ok
return true ;
}
2015-12-16 09:04:47 -05:00
bool cLuaState : : CheckParamBool ( int a_StartParam , int a_EndParam )
{
ASSERT ( IsValid ( ) ) ;
2016-02-05 16:45:45 -05:00
2015-12-16 09:04:47 -05:00
if ( a_EndParam < 0 )
{
a_EndParam = a_StartParam ;
}
2016-02-05 16:45:45 -05:00
2015-12-16 09:04:47 -05:00
tolua_Error tolua_err ;
for ( int i = a_StartParam ; i < = a_EndParam ; i + + )
{
if ( tolua_isboolean ( m_LuaState , i , 0 , & tolua_err ) )
{
continue ;
}
// Not the correct parameter
lua_Debug entry ;
VERIFY ( lua_getstack ( m_LuaState , 0 , & entry ) ) ;
VERIFY ( lua_getinfo ( m_LuaState , " n " , & entry ) ) ;
AString ErrMsg = Printf ( " #ferror in function '%s'. " , ( entry . name ! = nullptr ) ? entry . name : " ? " ) ;
tolua_error ( m_LuaState , ErrMsg . c_str ( ) , & tolua_err ) ;
return false ;
} // for i - Param
2016-02-05 16:45:45 -05:00
2015-12-16 09:04:47 -05:00
// All params checked ok
return true ;
}
2013-11-22 14:11:24 -05:00
bool cLuaState : : CheckParamString ( int a_StartParam , int a_EndParam )
{
ASSERT ( IsValid ( ) ) ;
2016-02-05 16:45:45 -05:00
2013-11-22 14:11:24 -05:00
if ( a_EndParam < 0 )
{
a_EndParam = a_StartParam ;
}
2016-02-05 16:45:45 -05:00
2013-11-22 14:11:24 -05:00
tolua_Error tolua_err ;
for ( int i = a_StartParam ; i < = a_EndParam ; i + + )
{
2015-09-28 08:53:50 -04:00
if ( lua_isstring ( m_LuaState , i ) )
2013-11-22 14:11:24 -05:00
{
continue ;
}
// Not the correct parameter
lua_Debug entry ;
VERIFY ( lua_getstack ( m_LuaState , 0 , & entry ) ) ;
VERIFY ( lua_getinfo ( m_LuaState , " n " , & entry ) ) ;
2015-09-28 08:53:50 -04:00
tolua_err . array = 0 ;
tolua_err . type = " string " ;
tolua_err . index = i ;
2014-10-20 16:55:07 -04:00
AString ErrMsg = Printf ( " #ferror in function '%s'. " , ( entry . name ! = nullptr ) ? entry . name : " ? " ) ;
2013-11-22 14:11:24 -05:00
tolua_error ( m_LuaState , ErrMsg . c_str ( ) , & tolua_err ) ;
return false ;
} // for i - Param
2016-02-05 16:45:45 -05:00
2013-11-22 14:11:24 -05:00
// All params checked ok
return true ;
}
2014-01-19 17:45:26 -05:00
bool cLuaState : : CheckParamFunction ( int a_StartParam , int a_EndParam )
{
ASSERT ( IsValid ( ) ) ;
2016-02-05 16:45:45 -05:00
2014-01-19 17:45:26 -05:00
if ( a_EndParam < 0 )
{
a_EndParam = a_StartParam ;
}
2016-02-05 16:45:45 -05:00
2014-01-19 17:45:26 -05:00
for ( int i = a_StartParam ; i < = a_EndParam ; i + + )
{
if ( lua_isfunction ( m_LuaState , i ) )
{
continue ;
}
// Not the correct parameter
lua_Debug entry ;
VERIFY ( lua_getstack ( m_LuaState , 0 , & entry ) ) ;
VERIFY ( lua_getinfo ( m_LuaState , " n " , & entry ) ) ;
2014-02-11 09:03:35 -05:00
luaL_error ( m_LuaState , " Error in function '%s' parameter #%d. Function expected, got %s " ,
2014-10-20 16:55:07 -04:00
( entry . name ! = nullptr ) ? entry . name : " ? " , i , GetTypeText ( i ) . c_str ( )
2014-02-11 09:03:35 -05:00
) ;
return false ;
} // for i - Param
2016-02-05 16:45:45 -05:00
2014-02-11 09:03:35 -05:00
// All params checked ok
return true ;
}
bool cLuaState : : CheckParamFunctionOrNil ( int a_StartParam , int a_EndParam )
{
ASSERT ( IsValid ( ) ) ;
2016-02-05 16:45:45 -05:00
2014-02-11 09:03:35 -05:00
if ( a_EndParam < 0 )
{
a_EndParam = a_StartParam ;
}
2016-02-05 16:45:45 -05:00
2014-02-11 09:03:35 -05:00
for ( int i = a_StartParam ; i < = a_EndParam ; i + + )
{
if ( lua_isfunction ( m_LuaState , i ) | | lua_isnil ( m_LuaState , i ) )
{
continue ;
}
// Not the correct parameter
lua_Debug entry ;
VERIFY ( lua_getstack ( m_LuaState , 0 , & entry ) ) ;
VERIFY ( lua_getinfo ( m_LuaState , " n " , & entry ) ) ;
luaL_error ( m_LuaState , " Error in function '%s' parameter #%d. Function expected, got %s " ,
2014-10-20 16:55:07 -04:00
( entry . name ! = nullptr ) ? entry . name : " ? " , i , GetTypeText ( i ) . c_str ( )
2014-01-19 17:45:26 -05:00
) ;
return false ;
} // for i - Param
2016-02-05 16:45:45 -05:00
2014-01-19 17:45:26 -05:00
// All params checked ok
return true ;
}
2013-08-07 08:26:18 -04:00
bool cLuaState : : CheckParamEnd ( int a_Param )
{
tolua_Error tolua_err ;
2015-05-08 18:32:02 -04:00
if ( tolua_isnoobj ( m_LuaState , a_Param , & tolua_err ) = = 1 )
2013-08-07 08:26:18 -04:00
{
return true ;
}
// Not the correct parameter
lua_Debug entry ;
VERIFY ( lua_getstack ( m_LuaState , 0 , & entry ) ) ;
VERIFY ( lua_getinfo ( m_LuaState , " n " , & entry ) ) ;
2014-10-20 16:55:07 -04:00
AString ErrMsg = Printf ( " #ferror in function '%s': Too many arguments. " , ( entry . name ! = nullptr ) ? entry . name : " ? " ) ;
2013-08-07 08:26:18 -04:00
tolua_error ( m_LuaState , ErrMsg . c_str ( ) , & tolua_err ) ;
return false ;
}
2015-03-21 13:17:26 -04:00
bool cLuaState : : IsParamUserType ( int a_Param , AString a_UserType )
{
ASSERT ( IsValid ( ) ) ;
2016-02-05 16:45:45 -05:00
2015-03-21 13:17:26 -04:00
tolua_Error tolua_err ;
2015-05-08 18:32:02 -04:00
return ( tolua_isusertype ( m_LuaState , a_Param , a_UserType . c_str ( ) , 0 , & tolua_err ) = = 1 ) ;
2015-03-21 13:17:26 -04:00
}
bool cLuaState : : IsParamNumber ( int a_Param )
{
ASSERT ( IsValid ( ) ) ;
2016-02-05 16:45:45 -05:00
2015-03-21 13:17:26 -04:00
tolua_Error tolua_err ;
2015-05-08 18:32:02 -04:00
return ( tolua_isnumber ( m_LuaState , a_Param , 0 , & tolua_err ) = = 1 ) ;
2015-03-21 13:17:26 -04:00
}
2013-08-04 17:11:25 -04:00
bool cLuaState : : ReportErrors ( int a_Status )
{
return ReportErrors ( m_LuaState , a_Status ) ;
}
bool cLuaState : : ReportErrors ( lua_State * a_LuaState , int a_Status )
{
if ( a_Status = = 0 )
{
// No error to report
return false ;
}
2016-02-05 16:45:45 -05:00
2013-08-04 17:11:25 -04:00
LOGWARNING ( " LUA: %d - %s " , a_Status , lua_tostring ( a_LuaState , - 1 ) ) ;
lua_pop ( a_LuaState , 1 ) ;
return true ;
}
2013-08-07 08:26:18 -04:00
2014-03-19 17:55:47 -04:00
void cLuaState : : LogStackTrace ( int a_StartingDepth )
2014-01-11 16:51:10 -05:00
{
2014-03-19 17:55:47 -04:00
LogStackTrace ( m_LuaState , a_StartingDepth ) ;
2014-01-11 16:51:10 -05:00
}
2014-03-19 17:55:47 -04:00
void cLuaState : : LogStackTrace ( lua_State * a_LuaState , int a_StartingDepth )
2013-08-21 14:06:37 -04:00
{
LOGWARNING ( " Stack trace: " ) ;
lua_Debug entry ;
2014-03-19 17:55:47 -04:00
int depth = a_StartingDepth ;
2014-01-11 16:51:10 -05:00
while ( lua_getstack ( a_LuaState , depth , & entry ) )
2013-08-21 14:06:37 -04:00
{
2014-02-04 16:24:03 -05:00
lua_getinfo ( a_LuaState , " Sln " , & entry ) ;
2014-01-11 16:51:10 -05:00
LOGWARNING ( " %s(%d): %s " , entry . short_src , entry . currentline , entry . name ? entry . name : " (no name) " ) ;
2013-08-21 14:06:37 -04:00
depth + + ;
}
LOGWARNING ( " Stack trace end " ) ;
}
AString cLuaState : : GetTypeText ( int a_StackPos )
{
2014-01-21 16:59:08 -05:00
return lua_typename ( m_LuaState , lua_type ( m_LuaState , a_StackPos ) ) ;
}
int cLuaState : : CallFunctionWithForeignParams (
const AString & a_FunctionName ,
cLuaState & a_SrcLuaState ,
int a_SrcParamStart ,
int a_SrcParamEnd
)
{
ASSERT ( IsValid ( ) ) ;
ASSERT ( a_SrcLuaState . IsValid ( ) ) ;
2016-02-05 16:45:45 -05:00
2014-01-21 16:59:08 -05:00
// Store the stack position before any changes
int OldTop = lua_gettop ( m_LuaState ) ;
2016-02-05 16:45:45 -05:00
2014-01-21 16:59:08 -05:00
// Push the function to call, including the error handler:
if ( ! PushFunction ( a_FunctionName . c_str ( ) ) )
{
LOGWARNING ( " Function '%s' not found " , a_FunctionName . c_str ( ) ) ;
2015-05-07 17:02:18 -04:00
lua_settop ( m_LuaState , OldTop ) ;
2014-01-21 16:59:08 -05:00
return - 1 ;
}
// Copy the function parameters to the target state
if ( CopyStackFrom ( a_SrcLuaState , a_SrcParamStart , a_SrcParamEnd ) < 0 )
2013-08-21 14:06:37 -04:00
{
2014-01-21 16:59:08 -05:00
// Something went wrong, fix the stack and exit
2015-05-07 17:02:18 -04:00
lua_settop ( m_LuaState , OldTop ) ;
2014-02-04 03:18:32 -05:00
m_NumCurrentFunctionArgs = - 1 ;
m_CurrentFunctionName . clear ( ) ;
2014-01-21 16:59:08 -05:00
return - 1 ;
}
2016-02-05 16:45:45 -05:00
2014-01-21 16:59:08 -05:00
// Call the function, with an error handler:
2014-02-04 04:29:10 -05:00
int s = lua_pcall ( m_LuaState , a_SrcParamEnd - a_SrcParamStart + 1 , LUA_MULTRET , OldTop + 1 ) ;
2014-01-21 16:59:08 -05:00
if ( ReportErrors ( s ) )
{
LOGWARN ( " Error while calling function '%s' in '%s' " , a_FunctionName . c_str ( ) , m_SubsystemName . c_str ( ) ) ;
2015-05-07 17:02:18 -04:00
// Reset the stack:
lua_settop ( m_LuaState , OldTop ) ;
2016-02-05 16:45:45 -05:00
2014-02-04 03:18:32 -05:00
// Reset the internal checking mechanisms:
m_NumCurrentFunctionArgs = - 1 ;
m_CurrentFunctionName . clear ( ) ;
2016-02-05 16:45:45 -05:00
2014-02-04 04:29:10 -05:00
// Make Lua think everything is okay and return 0 values, so that plugins continue executing.
// The failure is indicated by the zero return values.
return 0 ;
2013-08-21 14:06:37 -04:00
}
2016-02-05 16:45:45 -05:00
2014-01-21 16:59:08 -05:00
// Reset the internal checking mechanisms:
m_NumCurrentFunctionArgs = - 1 ;
2014-02-04 03:18:32 -05:00
m_CurrentFunctionName . clear ( ) ;
2016-02-05 16:45:45 -05:00
2014-01-21 16:59:08 -05:00
// Remove the error handler from the stack:
lua_remove ( m_LuaState , OldTop + 1 ) ;
2016-02-05 16:45:45 -05:00
2014-01-21 16:59:08 -05:00
// Return the number of return values:
return lua_gettop ( m_LuaState ) - OldTop ;
}
2016-05-30 19:01:55 -04:00
int cLuaState : : CopyStackFrom ( cLuaState & a_SrcLuaState , int a_SrcStart , int a_SrcEnd , int a_NumAllowedNestingLevels )
2014-01-21 16:59:08 -05:00
{
/*
// DEBUG:
LOGD ( " Copying stack values from %d to %d " , a_SrcStart , a_SrcEnd ) ;
a_SrcLuaState . LogStack ( " Src stack before copying: " ) ;
LogStack ( " Dst stack before copying: " ) ;
*/
for ( int i = a_SrcStart ; i < = a_SrcEnd ; + + i )
{
2016-05-30 19:01:55 -04:00
if ( ! CopySingleValueFrom ( a_SrcLuaState , i , a_NumAllowedNestingLevels ) )
2014-01-21 16:59:08 -05:00
{
2016-05-30 19:01:55 -04:00
lua_pop ( m_LuaState , i - a_SrcStart ) ;
return - 1 ;
}
}
return a_SrcEnd - a_SrcStart + 1 ;
}
bool cLuaState : : CopyTableFrom ( cLuaState & a_SrcLuaState , int a_SrcStackIdx , int a_NumAllowedNestingLevels )
{
// Create the dest table:
# ifdef _DEBUG
auto srcTop = lua_gettop ( a_SrcLuaState ) ;
auto dstTop = lua_gettop ( m_LuaState ) ;
# endif
lua_createtable ( m_LuaState , 0 , 0 ) ; // DST: <table>
lua_pushvalue ( a_SrcLuaState , a_SrcStackIdx ) ; // SRC: <table>
lua_pushnil ( a_SrcLuaState ) ; // SRC: <table> <key>
while ( lua_next ( a_SrcLuaState , - 2 ) ! = 0 ) // SRC: <table> <key> <value>
{
assert ( lua_gettop ( a_SrcLuaState ) = = srcTop + 3 ) ;
assert ( lua_gettop ( m_LuaState ) = = dstTop + 1 ) ;
// Copy the key:
if ( ! CopySingleValueFrom ( a_SrcLuaState , - 2 , a_NumAllowedNestingLevels ) ) // DST: <table> <key>
{
lua_pop ( m_LuaState , 1 ) ;
lua_pop ( a_SrcLuaState , 3 ) ;
assert ( lua_gettop ( a_SrcLuaState ) = = srcTop ) ;
assert ( lua_gettop ( m_LuaState ) = = dstTop ) ;
return false ;
}
assert ( lua_gettop ( a_SrcLuaState ) = = srcTop + 3 ) ;
assert ( lua_gettop ( m_LuaState ) = = dstTop + 2 ) ;
// Copy the value:
if ( ! CopySingleValueFrom ( a_SrcLuaState , - 1 , a_NumAllowedNestingLevels - 1 ) ) // DST: <table> <key> <value>
{
lua_pop ( m_LuaState , 2 ) ; // DST: empty
lua_pop ( a_SrcLuaState , 3 ) ; // SRC: empty
assert ( lua_gettop ( a_SrcLuaState ) = = srcTop ) ;
assert ( lua_gettop ( m_LuaState ) = = dstTop ) ;
return false ;
}
assert ( lua_gettop ( a_SrcLuaState ) = = srcTop + 3 ) ;
assert ( lua_gettop ( m_LuaState ) = = dstTop + 3 ) ;
// Set the value and fix up stacks:
lua_rawset ( m_LuaState , - 3 ) ; // DST: <table>
lua_pop ( a_SrcLuaState , 1 ) ; // SRC: <table> <key>
assert ( lua_gettop ( a_SrcLuaState ) = = srcTop + 2 ) ;
assert ( lua_gettop ( m_LuaState ) = = dstTop + 1 ) ;
}
lua_pop ( a_SrcLuaState , 1 ) ; // SRC: empty
assert ( lua_gettop ( a_SrcLuaState ) = = srcTop ) ;
assert ( lua_gettop ( m_LuaState ) = = dstTop + 1 ) ;
return true ;
}
bool cLuaState : : CopySingleValueFrom ( cLuaState & a_SrcLuaState , int a_StackIdx , int a_NumAllowedNestingLevels )
{
int t = lua_type ( a_SrcLuaState , a_StackIdx ) ;
switch ( t )
{
case LUA_TNIL :
{
lua_pushnil ( m_LuaState ) ;
return true ;
}
case LUA_TSTRING :
{
AString s ;
a_SrcLuaState . ToString ( a_StackIdx , s ) ;
Push ( s ) ;
return true ;
}
case LUA_TBOOLEAN :
{
bool b = ( tolua_toboolean ( a_SrcLuaState , a_StackIdx , false ) ! = 0 ) ;
Push ( b ) ;
return true ;
}
case LUA_TNUMBER :
{
lua_Number d = tolua_tonumber ( a_SrcLuaState , a_StackIdx , 0 ) ;
Push ( d ) ;
return true ;
}
case LUA_TUSERDATA :
{
// Get the class name:
const char * type = nullptr ;
if ( lua_getmetatable ( a_SrcLuaState , a_StackIdx ) = = 0 )
2014-01-21 16:59:08 -05:00
{
2016-05-30 19:01:55 -04:00
LOGWARNING ( " %s: Unknown class in pos %d, cannot copy. " , __FUNCTION__ , a_StackIdx ) ;
return false ;
2014-01-21 16:59:08 -05:00
}
2016-05-30 19:01:55 -04:00
lua_rawget ( a_SrcLuaState , LUA_REGISTRYINDEX ) ; // Stack +1
type = lua_tostring ( a_SrcLuaState , - 1 ) ;
lua_pop ( a_SrcLuaState , 1 ) ; // Stack -1
// Copy the value:
void * ud = tolua_touserdata ( a_SrcLuaState , a_StackIdx , nullptr ) ;
tolua_pushusertype ( m_LuaState , ud , type ) ;
return true ;
}
case LUA_TTABLE :
{
if ( ! CopyTableFrom ( a_SrcLuaState , a_StackIdx , a_NumAllowedNestingLevels - 1 ) )
2014-01-21 16:59:08 -05:00
{
2016-05-30 19:01:55 -04:00
LOGWARNING ( " %s: Failed to copy table in pos %d. " , __FUNCTION__ , a_StackIdx ) ;
return false ;
2014-01-21 16:59:08 -05:00
}
2016-05-30 19:01:55 -04:00
return true ;
}
default :
{
LOGWARNING ( " %s: Unsupported value: '%s' at stack position %d. Can only copy numbers, strings, bools, classes and simple tables! " ,
__FUNCTION__ , lua_typename ( a_SrcLuaState , t ) , a_StackIdx
) ;
return false ;
2014-01-21 16:59:08 -05:00
}
}
}
void cLuaState : : ToString ( int a_StackPos , AString & a_String )
{
size_t len ;
const char * s = lua_tolstring ( m_LuaState , a_StackPos , & len ) ;
2014-10-20 16:55:07 -04:00
if ( s ! = nullptr )
2014-01-21 16:59:08 -05:00
{
a_String . assign ( s , len ) ;
}
}
2016-06-10 15:30:07 -04:00
void cLuaState : : LogStackValues ( const char * a_Header )
2014-01-21 16:59:08 -05:00
{
2016-06-10 15:30:07 -04:00
LogStackValues ( m_LuaState , a_Header ) ;
2014-01-21 16:59:08 -05:00
}
2016-06-10 15:30:07 -04:00
void cLuaState : : LogStackValues ( lua_State * a_LuaState , const char * a_Header )
2014-01-21 16:59:08 -05:00
{
2014-03-11 17:16:08 -04:00
// Format string consisting only of %s is used to appease the compiler
2014-10-20 16:55:07 -04:00
LOG ( " %s " , ( a_Header ! = nullptr ) ? a_Header : " Lua C API Stack contents: " ) ;
2014-02-10 16:44:56 -05:00
for ( int i = lua_gettop ( a_LuaState ) ; i > 0 ; i - - )
2014-01-21 16:59:08 -05:00
{
AString Value ;
int Type = lua_type ( a_LuaState , i ) ;
switch ( Type )
{
case LUA_TBOOLEAN : Value . assign ( ( lua_toboolean ( a_LuaState , i ) ! = 0 ) ? " true " : " false " ) ; break ;
case LUA_TLIGHTUSERDATA : Printf ( Value , " %p " , lua_touserdata ( a_LuaState , i ) ) ; break ;
2015-07-29 11:04:03 -04:00
case LUA_TNUMBER : Printf ( Value , " %f " , static_cast < double > ( lua_tonumber ( a_LuaState , i ) ) ) ; break ;
2014-01-21 16:59:08 -05:00
case LUA_TSTRING : Printf ( Value , " %s " , lua_tostring ( a_LuaState , i ) ) ; break ;
2014-02-17 17:12:46 -05:00
case LUA_TTABLE : Printf ( Value , " %p " , lua_topointer ( a_LuaState , i ) ) ; break ;
2016-06-05 11:20:50 -04:00
case LUA_TUSERDATA : Printf ( Value , " %p (%s) " , lua_touserdata ( a_LuaState , i ) , tolua_typename ( a_LuaState , i ) ) ; break ;
2014-01-21 16:59:08 -05:00
default : break ;
}
LOGD ( " Idx %d: type %d (%s) %s " , i , Type , lua_typename ( a_LuaState , Type ) , Value . c_str ( ) ) ;
} // for i - stack idx
2013-08-21 14:06:37 -04:00
}
2016-06-10 15:30:07 -04:00
cLuaState * cLuaState : : QueryCanonLuaState ( void )
{
// Get the CanonLuaState global from Lua:
auto cb = WalkToNamedGlobal ( g_CanonLuaStateGlobalName ) ;
if ( ! cb . IsValid ( ) )
{
return nullptr ;
}
return reinterpret_cast < cLuaState * > ( lua_touserdata ( m_LuaState , - 1 ) ) ;
}
2014-01-11 17:10:40 -05:00
int cLuaState : : ReportFnCallErrors ( lua_State * a_LuaState )
{
LOGWARNING ( " LUA: %s " , lua_tostring ( a_LuaState , - 1 ) ) ;
2014-03-19 17:55:47 -04:00
LogStackTrace ( a_LuaState , 1 ) ;
2015-05-16 10:19:18 -04:00
BreakIntoDebugger ( a_LuaState ) ;
2014-01-11 17:10:40 -05:00
return 1 ; // We left the error message on the stack as the return value
}
2015-05-16 10:19:18 -04:00
int cLuaState : : BreakIntoDebugger ( lua_State * a_LuaState )
{
// Call the BreakIntoDebugger function, if available:
lua_getglobal ( a_LuaState , " BreakIntoDebugger " ) ;
if ( ! lua_isfunction ( a_LuaState , - 1 ) )
{
LOGD ( " LUA: BreakIntoDebugger() not found / not a function " ) ;
lua_pop ( a_LuaState , 1 ) ;
return 1 ;
}
lua_insert ( a_LuaState , - 2 ) ; // Copy the string that has been passed to us
LOGD ( " Calling BreakIntoDebugger()... " ) ;
lua_call ( a_LuaState , 1 , 0 ) ;
LOGD ( " Returned from BreakIntoDebugger(). " ) ;
return 0 ;
}
2016-03-02 05:34:39 -05:00
void cLuaState : : TrackCallback ( cCallback & a_Callback )
{
// Get the CanonLuaState global from Lua:
2016-06-10 15:30:07 -04:00
auto canonState = QueryCanonLuaState ( ) ;
if ( canonState = = nullptr )
2016-03-02 05:34:39 -05:00
{
LOGWARNING ( " %s: Lua state %p has invalid CanonLuaState! " , __FUNCTION__ , reinterpret_cast < void * > ( m_LuaState ) ) ;
return ;
}
// Add the callback:
2016-06-10 15:30:07 -04:00
cCSLock Lock ( canonState - > m_CSTrackedCallbacks ) ;
canonState - > m_TrackedCallbacks . push_back ( & a_Callback ) ;
2016-03-02 05:34:39 -05:00
}
void cLuaState : : UntrackCallback ( cCallback & a_Callback )
{
// Get the CanonLuaState global from Lua:
2016-06-10 15:30:07 -04:00
auto canonState = QueryCanonLuaState ( ) ;
if ( canonState = = nullptr )
2016-03-02 05:34:39 -05:00
{
LOGWARNING ( " %s: Lua state %p has invalid CanonLuaState! " , __FUNCTION__ , reinterpret_cast < void * > ( m_LuaState ) ) ;
return ;
}
// Remove the callback:
2016-06-10 15:30:07 -04:00
cCSLock Lock ( canonState - > m_CSTrackedCallbacks ) ;
auto & trackedCallbacks = canonState - > m_TrackedCallbacks ;
2016-03-02 05:34:39 -05:00
trackedCallbacks . erase ( std : : remove_if ( trackedCallbacks . begin ( ) , trackedCallbacks . end ( ) ,
[ & a_Callback ] ( cCallback * a_StoredCallback )
{
return ( a_StoredCallback = = & a_Callback ) ;
}
) ) ;
}
2014-07-17 16:15:34 -04:00
////////////////////////////////////////////////////////////////////////////////
2013-08-07 08:26:18 -04:00
// cLuaState::cRef:
2014-02-09 12:39:22 -05:00
cLuaState : : cRef : : cRef ( void ) :
2014-10-20 16:55:07 -04:00
m_LuaState ( nullptr ) ,
2014-02-09 12:39:22 -05:00
m_Ref ( LUA_REFNIL )
{
}
2013-08-07 08:26:18 -04:00
cLuaState : : cRef : : cRef ( cLuaState & a_LuaState , int a_StackPos ) :
2014-10-20 16:55:07 -04:00
m_LuaState ( nullptr ) ,
2014-02-09 12:39:22 -05:00
m_Ref ( LUA_REFNIL )
2013-08-07 08:26:18 -04:00
{
2014-02-09 12:39:22 -05:00
RefStack ( a_LuaState , a_StackPos ) ;
2013-08-07 08:26:18 -04:00
}
2015-01-30 15:24:02 -05:00
cLuaState : : cRef : : cRef ( cRef & & a_FromRef ) :
m_LuaState ( a_FromRef . m_LuaState ) ,
m_Ref ( a_FromRef . m_Ref )
{
a_FromRef . m_LuaState = nullptr ;
a_FromRef . m_Ref = LUA_REFNIL ;
}
2013-08-07 08:26:18 -04:00
cLuaState : : cRef : : ~ cRef ( )
{
2014-10-20 16:55:07 -04:00
if ( m_LuaState ! = nullptr )
2014-02-09 12:39:22 -05:00
{
UnRef ( ) ;
}
}
void cLuaState : : cRef : : RefStack ( cLuaState & a_LuaState , int a_StackPos )
{
ASSERT ( a_LuaState . IsValid ( ) ) ;
2014-10-20 16:55:07 -04:00
if ( m_LuaState ! = nullptr )
2014-02-09 12:39:22 -05:00
{
UnRef ( ) ;
}
2016-03-02 05:34:39 -05:00
m_LuaState = a_LuaState ;
2014-02-09 12:39:22 -05:00
lua_pushvalue ( a_LuaState , a_StackPos ) ; // Push a copy of the value at a_StackPos onto the stack
m_Ref = luaL_ref ( a_LuaState , LUA_REGISTRYINDEX ) ;
}
void cLuaState : : cRef : : UnRef ( void )
{
2013-08-07 08:26:18 -04:00
if ( IsValid ( ) )
{
2016-03-02 05:34:39 -05:00
luaL_unref ( m_LuaState , LUA_REGISTRYINDEX , m_Ref ) ;
2013-08-07 08:26:18 -04:00
}
2014-10-20 16:55:07 -04:00
m_LuaState = nullptr ;
2014-02-09 12:39:22 -05:00
m_Ref = LUA_REFNIL ;
2013-08-07 08:26:18 -04:00
}