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"
2014-10-19 05:46:38 -04:00
# include "../Entities/Entity.h"
# include "../BlockEntities/BlockEntity.h"
2013-08-04 17:11:25 -04: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
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 ;
}
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 ) ;
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. " ,
__FUNCTION__ , m_LuaState
) ;
Detach ( ) ;
return ;
}
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
{
LOGINFO ( " %s: Already contains a LuaState (0x%p), will be closed / detached. " , __FUNCTION__ , m_LuaState ) ;
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). " ,
__FUNCTION__ , m_LuaState
) ;
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 ) ;
// Append the new path:
AString NewPackagePath ( PackagePath , len ) ;
NewPackagePath . append ( LUA_PATHSEP ) ;
NewPackagePath . append ( a_Path ) ;
// 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 ( ) ) ;
// 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 ;
}
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 ;
}
2014-01-11 17:10:40 -05:00
// Push the error handler for lua_pcall()
lua_pushcfunction ( m_LuaState , & ReportFnCallErrors ) ;
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 ;
}
2013-08-08 10:02:07 -04:00
bool cLuaState : : PushFunction ( int 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
2014-01-11 17:10:40 -05:00
// Push the error handler for lua_pcall()
lua_pushcfunction ( m_LuaState , & ReportFnCallErrors ) ;
2013-08-04 17:11:25 -04:00
lua_rawgeti ( m_LuaState , LUA_REGISTRYINDEX , a_FnRef ) ; // same as lua_getref()
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
2014-01-11 16:51:10 -05:00
2014-01-11 17:10:40 -05:00
// Push the error handler for lua_pcall()
lua_pushcfunction ( m_LuaState , & ReportFnCallErrors ) ;
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 ;
}
2014-01-29 16:56:23 -05:00
// Pop the table off the stack:
lua_remove ( m_LuaState , - 2 ) ;
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 ( ) ) ;
2013-12-27 05:51:08 -05:00
lua_createtable ( m_LuaState , ( 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 ( ) ) ;
2014-06-03 13:29:04 -04:00
tolua_pushusertype ( m_LuaState , ( void * ) 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 ( ) ) ;
2014-06-03 13:29:04 -04:00
tolua_pushusertype ( m_LuaState , ( void * ) 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 ( ) ) ;
2014-06-03 13:29:04 -04:00
tolua_pushusertype ( m_LuaState , ( void * ) & 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 ( ) ) ;
2014-06-03 13:29:04 -04:00
tolua_pushusertype ( m_LuaState , ( void * ) 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 ( ) ) ;
2014-06-03 13:29:04 -04:00
tolua_pushusertype ( m_LuaState , ( void * ) 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 ( ) ) ;
2014-06-03 13:29:04 -04:00
tolua_pushusertype ( m_LuaState , ( void * ) 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 ( ) ) ;
2014-08-22 04:33:15 -04:00
tolua_pushusertype ( m_LuaState , ( void * ) & a_Vector , " Vector3<double> " ) ;
m_NumCurrentFunctionArgs + = 1 ;
}
void cLuaState : : Push ( const Vector3d * a_Vector )
{
ASSERT ( IsValid ( ) ) ;
tolua_pushusertype ( m_LuaState , ( void * ) a_Vector , " Vector3<double> " ) ;
m_NumCurrentFunctionArgs + = 1 ;
}
void cLuaState : : Push ( const Vector3i & a_Vector )
{
ASSERT ( IsValid ( ) ) ;
tolua_pushusertype ( m_LuaState , ( void * ) & a_Vector , " Vector3<int> " ) ;
m_NumCurrentFunctionArgs + = 1 ;
}
void cLuaState : : Push ( const Vector3i * a_Vector )
{
ASSERT ( IsValid ( ) ) ;
tolua_pushusertype ( m_LuaState , ( void * ) 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 ;
}
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
void cLuaState : : Push ( void * a_Ptr )
{
2014-03-07 13:26:07 -05:00
UNUSED ( a_Ptr ) ;
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
ASSERT ( IsValid ( ) ) ;
2014-02-26 15:37:38 -05:00
// Investigate the cause of this - what is the callstack?
2014-03-20 04:16:47 -04:00
// One code path leading here is the OnHookExploding / OnHookExploded with exotic parameters. Need to decide what to do with them
LOGWARNING ( " Lua engine: attempting to push a plain pointer, pushing nil instead. " ) ;
LOGWARNING ( " This indicates an unimplemented part of MCS bindings " ) ;
2014-02-26 15:37:38 -05:00
LogStackTrace ( ) ;
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
lua_pushnil ( m_LuaState ) ;
m_NumCurrentFunctionArgs + = 1 ;
}
2015-05-12 03:20:54 -04:00
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
2015-05-12 03:20:54 -04:00
/*
2014-06-03 13:29:04 -04:00
void cLuaState : : PushUserType ( void * a_Object , const char * a_Type )
2013-08-11 08:57:07 -04:00
{
ASSERT ( IsValid ( ) ) ;
2014-06-03 13:29:04 -04:00
tolua_pushusertype ( m_LuaState , a_Object , a_Type ) ;
2013-08-11 08:57:07 -04:00
m_NumCurrentFunctionArgs + = 1 ;
}
2015-05-12 03:20:54 -04:00
*/
2013-08-11 08:57:07 -04:00
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
}
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[]
return std : : move ( cStackValue ( * this ) ) ;
}
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
2013-08-04 17:11:25 -04: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 ;
// 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 ;
}
2014-01-21 16:59:08 -05:00
// Remove the error handler from the stack:
lua_remove ( m_LuaState , - a_NumResults - 1 ) ;
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 ( ) ) ;
if ( a_EndParam < 0 )
{
a_EndParam = a_StartParam ;
}
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
// 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 ( ) ) ;
if ( a_EndParam < 0 )
{
a_EndParam = a_StartParam ;
}
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
// All params checked ok
return true ;
}
bool cLuaState : : CheckParamTable ( int a_StartParam , int a_EndParam )
{
ASSERT ( IsValid ( ) ) ;
if ( a_EndParam < 0 )
{
a_EndParam = a_StartParam ;
}
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
// All params checked ok
return true ;
}
bool cLuaState : : CheckParamNumber ( int a_StartParam , int a_EndParam )
{
ASSERT ( IsValid ( ) ) ;
if ( a_EndParam < 0 )
{
a_EndParam = a_StartParam ;
}
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
// 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 ( ) ) ;
if ( a_EndParam < 0 )
{
a_EndParam = a_StartParam ;
}
tolua_Error tolua_err ;
for ( int i = a_StartParam ; i < = a_EndParam ; i + + )
{
if ( tolua_isstring ( 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-11-22 14:11:24 -05:00
tolua_error ( m_LuaState , ErrMsg . c_str ( ) , & tolua_err ) ;
return false ;
} // for i - Param
// 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 ( ) ) ;
if ( a_EndParam < 0 )
{
a_EndParam = a_StartParam ;
}
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
// All params checked ok
return true ;
}
bool cLuaState : : CheckParamFunctionOrNil ( int a_StartParam , int a_EndParam )
{
ASSERT ( IsValid ( ) ) ;
if ( a_EndParam < 0 )
{
a_EndParam = a_StartParam ;
}
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
// 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 ( ) ) ;
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 ( ) ) ;
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 ;
}
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 ( ) ) ;
// Store the stack position before any changes
int OldTop = lua_gettop ( m_LuaState ) ;
// 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 ;
}
// 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 ) ;
2014-02-04 03:18:32 -05:00
// Reset the internal checking mechanisms:
m_NumCurrentFunctionArgs = - 1 ;
m_CurrentFunctionName . clear ( ) ;
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
}
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 ( ) ;
2014-01-21 16:59:08 -05:00
// Remove the error handler from the stack:
lua_remove ( m_LuaState , OldTop + 1 ) ;
// Return the number of return values:
return lua_gettop ( m_LuaState ) - OldTop ;
}
int cLuaState : : CopyStackFrom ( cLuaState & a_SrcLuaState , int a_SrcStart , int a_SrcEnd )
{
/*
// 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 )
{
int t = lua_type ( a_SrcLuaState , i ) ;
switch ( t )
{
case LUA_TNIL :
{
lua_pushnil ( m_LuaState ) ;
break ;
}
case LUA_TSTRING :
{
AString s ;
a_SrcLuaState . ToString ( i , s ) ;
Push ( s ) ;
break ;
}
case LUA_TBOOLEAN :
{
bool b = ( tolua_toboolean ( a_SrcLuaState , i , false ) ! = 0 ) ;
Push ( b ) ;
break ;
}
case LUA_TNUMBER :
{
lua_Number d = tolua_tonumber ( a_SrcLuaState , i , 0 ) ;
Push ( d ) ;
break ;
}
case LUA_TUSERDATA :
{
// Get the class name:
2014-10-20 16:55:07 -04:00
const char * type = nullptr ;
2014-01-21 16:59:08 -05:00
if ( lua_getmetatable ( a_SrcLuaState , i ) = = 0 )
{
LOGWARNING ( " %s: Unknown class in pos %d, cannot copy. " , __FUNCTION__ , i ) ;
lua_pop ( m_LuaState , i - a_SrcStart ) ;
return - 1 ;
}
lua_rawget ( a_SrcLuaState , LUA_REGISTRYINDEX ) ; // Stack +1
type = lua_tostring ( a_SrcLuaState , - 1 ) ;
lua_pop ( a_SrcLuaState , 1 ) ; // Stack -1
// Copy the value:
2014-10-20 16:55:07 -04:00
void * ud = tolua_touserdata ( a_SrcLuaState , i , nullptr ) ;
2014-01-21 16:59:08 -05:00
tolua_pushusertype ( m_LuaState , ud , type ) ;
2014-02-04 08:26:36 -05:00
break ;
2014-01-21 16:59:08 -05:00
}
default :
{
LOGWARNING ( " %s: Unsupported value: '%s' at stack position %d. Can only copy numbers, strings, bools and classes! " ,
__FUNCTION__ , lua_typename ( a_SrcLuaState , t ) , i
) ;
a_SrcLuaState . LogStack ( " Stack where copying failed: " ) ;
lua_pop ( m_LuaState , i - a_SrcStart ) ;
return - 1 ;
}
}
}
return a_SrcEnd - a_SrcStart + 1 ;
}
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 ) ;
}
}
void cLuaState : : LogStack ( const char * a_Header )
{
LogStack ( m_LuaState , a_Header ) ;
}
void cLuaState : : LogStack ( lua_State * a_LuaState , const char * a_Header )
{
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 ;
case LUA_TNUMBER : Printf ( Value , " %f " , ( double ) lua_tonumber ( a_LuaState , i ) ) ; break ;
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 ;
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
}
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 ;
}
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 ( ) ;
}
m_LuaState = & a_LuaState ;
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 )
{
ASSERT ( m_LuaState - > IsValid ( ) ) ; // The reference should be destroyed before destroying the LuaState
2013-08-07 08:26:18 -04:00
if ( IsValid ( ) )
{
2014-02-09 12:39:22 -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
}