2013-08-04 23:11:25 +02: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 17:14:46 +00:00
#include "lua/src/lualib.h"
2013-08-04 23:11:25 +02:00
}
2014-03-25 11:15:05 -06:00
#undef TOLUA_TEMPLATE_BIND
2013-12-08 18:24:56 +01:00
#include "tolua++/include/tolua++.h"
2013-08-04 23:11:25 +02:00
#include "Bindings.h"
#include "ManualBindings.h"
2014-03-02 11:12:29 +02:00
#include "DeprecatedBindings.h"
2015-12-23 11:08:39 +01:00
#include "LuaJson.h"
2014-10-19 11:46:38 +02:00
#include "../Entities/Entity.h"
#include "../BlockEntities/BlockEntity.h"
2013-08-04 23:11:25 +02:00
2015-05-09 09:25:09 +02:00
// fwd: "SQLite/lsqlite3.c"
2013-08-04 23:11:25 +02:00
extern "C"
{
2013-12-27 11:51:08 +01:00
int luaopen_lsqlite3 ( lua_State * L );
2013-08-04 23:11:25 +02:00
}
2015-05-09 09:25:09 +02:00
// fwd: "LuaExpat/lxplib.c":
2013-08-04 23:11:25 +02:00
extern "C"
{
int luaopen_lxp ( lua_State * L );
}
2013-08-15 13:05:24 +02:00
const cLuaState :: cRet cLuaState :: Return = {};
2013-08-08 14:08:21 +02:00
2015-09-28 21:30:31 +02: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 ;
}
2014-07-17 22:15:34 +02:00
////////////////////////////////////////////////////////////////////////////////
2013-08-04 23:11:25 +02:00
// cLuaState:
cLuaState :: cLuaState ( const AString & a_SubsystemName ) :
2014-10-20 21:55:07 +01:00
m_LuaState ( nullptr ),
2013-08-06 08:01:00 +02:00
m_IsOwned ( false ),
2013-08-06 08:59:54 +02:00
m_SubsystemName ( a_SubsystemName ),
m_NumCurrentFunctionArgs ( - 1 )
2013-08-04 23:11:25 +02:00
{
}
2013-08-06 08:01:00 +02:00
cLuaState :: cLuaState ( lua_State * a_AttachState ) :
m_LuaState ( a_AttachState ),
m_IsOwned ( false ),
2013-08-06 08:59:54 +02:00
m_SubsystemName ( "<attached>" ),
m_NumCurrentFunctionArgs ( - 1 )
2013-08-06 08:01:00 +02:00
{
}
2013-08-04 23:11:25 +02:00
cLuaState ::~ cLuaState ()
{
if ( IsValid ())
{
2013-08-07 14:26:18 +02:00
if ( m_IsOwned )
{
Close ();
}
else
{
Detach ();
}
2013-08-04 23:11:25 +02:00
}
}
void cLuaState :: Create ( void )
{
2014-10-20 21:55:07 +01:00
if ( m_LuaState != nullptr )
2013-08-04 23:11:25 +02:00
{
LOGWARNING ( "%s: Trying to create an already-existing LuaState, ignoring." , __FUNCTION__ );
return ;
}
m_LuaState = lua_open ();
luaL_openlibs ( m_LuaState );
2014-03-12 13:05:28 +01:00
m_IsOwned = true ;
2015-09-28 21:30:31 +02:00
cLuaStateTracker :: Add ( * this );
2014-03-12 13:05:28 +01:00
}
void cLuaState :: RegisterAPILibs ( void )
{
2013-08-04 23:11:25 +02:00
tolua_AllToLua_open ( m_LuaState );
2015-05-13 11:30:57 +02:00
cManualBindings :: Bind ( m_LuaState );
2014-03-02 11:12:29 +02:00
DeprecatedBindings :: Bind ( m_LuaState );
2015-12-23 11:08:39 +01:00
cLuaJson :: Bind ( * this );
2013-08-04 23:11:25 +02:00
luaopen_lsqlite3 ( m_LuaState );
luaopen_lxp ( m_LuaState );
}
void cLuaState :: Close ( void )
{
2014-10-20 21:55:07 +01:00
if ( m_LuaState == nullptr )
2013-08-04 23:11:25 +02:00
{
LOGWARNING ( "%s: Trying to close an invalid LuaState, ignoring." , __FUNCTION__ );
return ;
}
2013-08-06 08:01:00 +02:00
if ( ! m_IsOwned )
{
LOGWARNING (
"%s: Detected mis-use, calling Close() on an attached state (0x%p). Detaching instead." ,
2015-09-24 16:04:44 +02:00
__FUNCTION__ , static_cast < void *> ( m_LuaState )
2013-08-06 08:01:00 +02:00
);
Detach ();
return ;
}
2015-09-28 21:30:31 +02:00
cLuaStateTracker :: Del ( * this );
2013-08-04 23:11:25 +02:00
lua_close ( m_LuaState );
2014-10-20 21:55:07 +01:00
m_LuaState = nullptr ;
2013-08-06 08:01:00 +02:00
m_IsOwned = false ;
}
void cLuaState :: Attach ( lua_State * a_State )
{
2014-10-20 21:55:07 +01:00
if ( m_LuaState != nullptr )
2013-08-06 08:01:00 +02:00
{
2015-09-24 16:04:44 +02:00
LOGINFO ( "%s: Already contains a LuaState (0x%p), will be closed / detached." , __FUNCTION__ , static_cast < void *> ( m_LuaState ));
2013-08-06 08:01:00 +02:00
if ( m_IsOwned )
{
Close ();
}
else
{
Detach ();
}
}
m_LuaState = a_State ;
m_IsOwned = false ;
}
void cLuaState :: Detach ( void )
{
2014-10-20 21:55:07 +01:00
if ( m_LuaState == nullptr )
2013-08-06 08:01:00 +02: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 16:04:44 +02:00
__FUNCTION__ , static_cast < void *> ( m_LuaState )
2013-08-06 08:01:00 +02:00
);
Close ();
return ;
}
2014-10-20 21:55:07 +01:00
m_LuaState = nullptr ;
2013-08-04 23:11:25 +02:00
}
2014-02-17 23:12:46 +01: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 23:45:45 +02:00
2014-02-17 23:12:46 +01:00
// Append the new path:
AString NewPackagePath ( PackagePath , len );
NewPackagePath . append ( LUA_PATHSEP );
NewPackagePath . append ( a_Path );
2016-02-05 23:45:45 +02:00
2014-02-17 23:12:46 +01: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 15:21:20 +02:00
bool cLuaState :: LoadFile ( const AString & a_FileName , bool a_LogWarnings )
2013-08-04 23:11:25 +02:00
{
ASSERT ( IsValid ());
2015-11-11 10:32:42 +01:00
2013-08-04 23:11:25 +02:00
// Load the file:
int s = luaL_loadfile ( m_LuaState , a_FileName . c_str ());
2015-06-17 15:21:20 +02:00
if ( s != 0 )
2013-08-04 23:11:25 +02:00
{
2015-06-17 15:21:20 +02: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 23:11:25 +02:00
return false ;
}
// Execute the globals:
s = lua_pcall ( m_LuaState , 0 , LUA_MULTRET , 0 );
2015-06-17 15:21:20 +02:00
if ( s != 0 )
2013-08-04 23:11:25 +02:00
{
2015-06-17 15:21:20 +02: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 23:11:25 +02:00
return false ;
}
2015-11-11 10:32:42 +01: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 23:11:25 +02:00
return true ;
}
2013-08-08 16:02:07 +02: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 23:11:25 +02:00
{
2013-08-06 08:59:54 +02:00
ASSERT ( m_NumCurrentFunctionArgs == - 1 ); // If not, there's already something pushed onto the stack
2013-08-04 23:11:25 +02:00
if ( ! IsValid ())
{
// This happens if cPlugin::Initialize() fails with an error
return false ;
}
2016-02-05 23:45:45 +02:00
2014-01-11 23:10:40 +01:00
// Push the error handler for lua_pcall()
lua_pushcfunction ( m_LuaState , & ReportFnCallErrors );
2016-02-05 23:45:45 +02:00
2013-08-04 23:11:25 +02:00
lua_getglobal ( m_LuaState , a_FunctionName );
if ( ! lua_isfunction ( m_LuaState , - 1 ))
{
2013-08-08 16:02:07 +02:00
LOGWARNING ( "Error in %s: Could not find function %s()" , m_SubsystemName . c_str (), a_FunctionName );
2014-01-21 22:59:08 +01:00
lua_pop ( m_LuaState , 2 );
2013-08-04 23:11:25 +02:00
return false ;
}
2013-08-06 08:59:54 +02:00
m_CurrentFunctionName . assign ( a_FunctionName );
m_NumCurrentFunctionArgs = 0 ;
2013-08-04 23:11:25 +02:00
return true ;
}
2013-08-08 16:02:07 +02:00
bool cLuaState :: PushFunction ( int a_FnRef )
2013-08-04 23:11:25 +02:00
{
2013-08-06 08:59:54 +02:00
ASSERT ( IsValid ());
ASSERT ( m_NumCurrentFunctionArgs == - 1 ); // If not, there's already something pushed onto the stack
2016-02-05 23:45:45 +02:00
2014-01-11 23:10:40 +01:00
// Push the error handler for lua_pcall()
lua_pushcfunction ( m_LuaState , & ReportFnCallErrors );
2016-02-05 23:45:45 +02:00
2013-08-04 23:11:25 +02:00
lua_rawgeti ( m_LuaState , LUA_REGISTRYINDEX , a_FnRef ); // same as lua_getref()
if ( ! lua_isfunction ( m_LuaState , - 1 ))
{
2014-01-21 22:59:08 +01:00
lua_pop ( m_LuaState , 2 );
2013-08-04 23:11:25 +02:00
return false ;
}
2013-08-06 08:59:54 +02:00
m_CurrentFunctionName = "<callback>" ;
m_NumCurrentFunctionArgs = 0 ;
2013-08-04 23:11:25 +02:00
return true ;
}
2014-01-11 22:51:10 +01:00
bool cLuaState :: PushFunction ( const cTableRef & a_TableRef )
2013-08-07 14:26:18 +02:00
{
ASSERT ( IsValid ());
ASSERT ( m_NumCurrentFunctionArgs == - 1 ); // If not, there's already something pushed onto the stack
2016-02-05 23:45:45 +02:00
2014-01-11 23:10:40 +01:00
// Push the error handler for lua_pcall()
lua_pushcfunction ( m_LuaState , & ReportFnCallErrors );
2016-02-05 23:45:45 +02:00
2014-01-11 22:51:10 +01:00
lua_rawgeti ( m_LuaState , LUA_REGISTRYINDEX , a_TableRef . GetTableRef ()); // Get the table ref
2013-08-07 14:26:18 +02:00
if ( ! lua_istable ( m_LuaState , - 1 ))
{
// Not a table, bail out
2014-01-21 22:59:08 +01:00
lua_pop ( m_LuaState , 2 );
2013-08-07 14:26:18 +02:00
return false ;
}
2014-01-11 22:51:10 +01:00
lua_getfield ( m_LuaState , - 1 , a_TableRef . GetFnName ());
2013-08-07 14:26:18 +02:00
if ( lua_isnil ( m_LuaState , - 1 ) || ! lua_isfunction ( m_LuaState , - 1 ))
{
// Not a valid function, bail out
2014-01-29 22:56:23 +01:00
lua_pop ( m_LuaState , 3 );
2013-08-07 14:26:18 +02:00
return false ;
}
2016-02-05 23:45:45 +02:00
2014-01-29 22:56:23 +01:00
// Pop the table off the stack:
lua_remove ( m_LuaState , - 2 );
2016-02-05 23:45:45 +02:00
2014-01-11 22:51:10 +01:00
Printf ( m_CurrentFunctionName , "<table-callback %s>" , a_TableRef . GetFnName ());
2013-08-07 14:26:18 +02:00
m_NumCurrentFunctionArgs = 0 ;
return true ;
}
2015-02-12 20:05:55 +01:00
void cLuaState :: PushNil ( void )
{
ASSERT ( IsValid ());
lua_pushnil ( m_LuaState );
m_NumCurrentFunctionArgs += 1 ;
}
2013-08-08 14:08:21 +02:00
void cLuaState :: Push ( const AString & a_String )
{
ASSERT ( IsValid ());
2014-01-07 15:55:23 +01:00
lua_pushlstring ( m_LuaState , a_String . data (), a_String . size ());
2013-08-08 14:08:21 +02:00
m_NumCurrentFunctionArgs += 1 ;
}
void cLuaState :: Push ( const AStringVector & a_Vector )
2013-08-04 23:11:25 +02:00
{
2013-08-06 08:59:54 +02:00
ASSERT ( IsValid ());
2015-07-29 09:04:03 -06:00
lua_createtable ( m_LuaState , static_cast < int > ( a_Vector . size ()), 0 );
2013-08-04 23:11:25 +02: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 08:59:54 +02:00
m_NumCurrentFunctionArgs += 1 ;
}
2014-06-03 19:29:04 +02:00
void cLuaState :: Push ( const cCraftingGrid * a_Grid )
2013-08-06 08:59:54 +02:00
{
ASSERT ( IsValid ());
2015-07-29 09:04:03 -06:00
tolua_pushusertype ( m_LuaState , reinterpret_cast < void *> ( const_cast < cCraftingGrid *> ( a_Grid )), "cCraftingGrid" );
2013-08-06 08:59:54 +02:00
m_NumCurrentFunctionArgs += 1 ;
}
2014-06-03 19:29:04 +02:00
void cLuaState :: Push ( const cCraftingRecipe * a_Recipe )
2013-08-06 08:59:54 +02:00
{
ASSERT ( IsValid ());
2015-07-29 09:04:03 -06:00
tolua_pushusertype ( m_LuaState , reinterpret_cast < void *> ( const_cast < cCraftingRecipe *> ( a_Recipe )), "cCraftingRecipe" );
2013-08-06 08:59:54 +02:00
m_NumCurrentFunctionArgs += 1 ;
}
2014-06-03 19:29:04 +02:00
void cLuaState :: Push ( const char * a_Value )
2013-08-06 08:59:54 +02:00
{
ASSERT ( IsValid ());
2014-06-03 19:29:04 +02:00
tolua_pushstring ( m_LuaState , a_Value );
2013-08-06 08:59:54 +02:00
m_NumCurrentFunctionArgs += 1 ;
}
2014-06-03 19:29:04 +02:00
void cLuaState :: Push ( const cItems & a_Items )
2013-08-06 08:59:54 +02:00
{
ASSERT ( IsValid ());
2015-07-29 09:04:03 -06:00
tolua_pushusertype ( m_LuaState , reinterpret_cast < void *> ( const_cast < cItems *> ( & a_Items )), "cItems" );
2013-08-06 08:59:54 +02:00
m_NumCurrentFunctionArgs += 1 ;
}
2014-06-03 19:29:04 +02:00
void cLuaState :: Push ( const cPlayer * a_Player )
2013-08-06 08:59:54 +02:00
{
ASSERT ( IsValid ());
2015-07-29 09:04:03 -06:00
tolua_pushusertype ( m_LuaState , reinterpret_cast < void *> ( const_cast < cPlayer *> ( a_Player )), "cPlayer" );
2013-08-06 08:59:54 +02:00
m_NumCurrentFunctionArgs += 1 ;
}
2015-06-17 15:21:20 +02: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 19:29:04 +02:00
void cLuaState :: Push ( const HTTPRequest * a_Request )
2013-08-06 08:59:54 +02:00
{
ASSERT ( IsValid ());
2015-07-29 09:04:03 -06:00
tolua_pushusertype ( m_LuaState , reinterpret_cast < void *> ( const_cast < HTTPRequest *> ( a_Request )), "HTTPRequest" );
2013-08-06 08:59:54 +02:00
m_NumCurrentFunctionArgs += 1 ;
}
2014-06-03 19:29:04 +02:00
void cLuaState :: Push ( const HTTPTemplateRequest * a_Request )
2013-08-06 08:59:54 +02:00
{
ASSERT ( IsValid ());
2015-07-29 09:04:03 -06:00
tolua_pushusertype ( m_LuaState , reinterpret_cast < void *> ( const_cast < HTTPTemplateRequest *> ( a_Request )), "HTTPTemplateRequest" );
2013-08-06 08:59:54 +02:00
m_NumCurrentFunctionArgs += 1 ;
}
2014-06-03 19:29:04 +02:00
void cLuaState :: Push ( const Vector3d & a_Vector )
2013-08-08 14:08:21 +02:00
{
ASSERT ( IsValid ());
2015-07-29 09:04:03 -06:00
tolua_pushusertype ( m_LuaState , reinterpret_cast < void *> ( const_cast < Vector3d *> ( & a_Vector )), "Vector3<double>" );
2014-08-22 10:33:15 +02:00
m_NumCurrentFunctionArgs += 1 ;
}
void cLuaState :: Push ( const Vector3d * a_Vector )
{
ASSERT ( IsValid ());
2015-07-29 09:04:03 -06:00
tolua_pushusertype ( m_LuaState , reinterpret_cast < void *> ( const_cast < Vector3d *> ( a_Vector )), "Vector3<double>" );
2014-08-22 10:33:15 +02:00
m_NumCurrentFunctionArgs += 1 ;
}
void cLuaState :: Push ( const Vector3i & a_Vector )
{
ASSERT ( IsValid ());
2015-07-29 09:04:03 -06:00
tolua_pushusertype ( m_LuaState , reinterpret_cast < void *> ( const_cast < Vector3i *> ( & a_Vector )), "Vector3<int>" );
2014-08-22 10:33:15 +02:00
m_NumCurrentFunctionArgs += 1 ;
}
void cLuaState :: Push ( const Vector3i * a_Vector )
{
ASSERT ( IsValid ());
2015-07-29 09:04:03 -06:00
tolua_pushusertype ( m_LuaState , reinterpret_cast < void *> ( const_cast < Vector3i *> ( a_Vector )), "Vector3<int>" );
2013-08-08 14:08:21 +02:00
m_NumCurrentFunctionArgs += 1 ;
}
2014-06-03 19:29:04 +02:00
void cLuaState :: Push ( bool a_Value )
2013-08-06 08:59:54 +02:00
{
ASSERT ( IsValid ());
2014-06-03 19:29:04 +02:00
tolua_pushboolean ( m_LuaState , a_Value ? 1 : 0 );
2013-08-06 08:59:54 +02:00
m_NumCurrentFunctionArgs += 1 ;
}
2014-06-03 19:29:04 +02:00
void cLuaState :: Push ( cEntity * a_Entity )
{
ASSERT ( IsValid ());
2014-10-20 17:32:09 +02:00
if ( a_Entity == nullptr )
{
lua_pushnil ( m_LuaState );
}
2014-10-19 12:49:54 +02:00
else
{
2014-10-21 12:43:06 +02: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 16:06:16 +02:00
tolua_pushusertype ( m_LuaState , a_Entity , a_Entity -> GetClass ());
2014-10-21 12:43:06 +02: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 12:49:54 +02:00
}
2014-10-21 12:43:06 +02:00
2014-06-03 19:29:04 +02:00
m_NumCurrentFunctionArgs += 1 ;
}
2015-01-30 21:24:02 +01:00
void cLuaState :: Push ( cLuaServerHandle * a_ServerHandle )
{
ASSERT ( IsValid ());
tolua_pushusertype ( m_LuaState , a_ServerHandle , "cServerHandle" );
m_NumCurrentFunctionArgs += 1 ;
}
2015-01-28 15:14:05 +01:00
void cLuaState :: Push ( cLuaTCPLink * a_TCPLink )
{
ASSERT ( IsValid ());
tolua_pushusertype ( m_LuaState , a_TCPLink , "cTCPLink" );
m_NumCurrentFunctionArgs += 1 ;
}
2015-02-20 14:28:05 +01:00
void cLuaState :: Push ( cLuaUDPEndpoint * a_UDPEndpoint )
{
ASSERT ( IsValid ());
tolua_pushusertype ( m_LuaState , a_UDPEndpoint , "cUDPEndpoint" );
m_NumCurrentFunctionArgs += 1 ;
}
2014-06-03 19:29:04 +02:00
void cLuaState :: Push ( double a_Value )
2013-08-08 16:02:07 +02:00
{
ASSERT ( IsValid ());
2014-06-03 19:29:04 +02:00
tolua_pushnumber ( m_LuaState , a_Value );
2013-08-08 16:02:07 +02:00
m_NumCurrentFunctionArgs += 1 ;
}
2014-06-03 19:29:04 +02:00
void cLuaState :: Push ( int a_Value )
2013-08-08 16:30:02 +02:00
{
ASSERT ( IsValid ());
2014-06-03 19:29:04 +02:00
tolua_pushnumber ( m_LuaState , a_Value );
2013-08-08 16:30:02 +02:00
m_NumCurrentFunctionArgs += 1 ;
}
2015-09-26 22:54:18 +02: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 09:04:03 -06:00
void cLuaState :: Push ( UInt32 a_Value )
{
ASSERT ( IsValid ());
tolua_pushnumber ( m_LuaState , a_Value );
m_NumCurrentFunctionArgs += 1 ;
}
2015-01-11 21:12:26 +00:00
void cLuaState :: Push ( std :: chrono :: milliseconds a_Value )
{
ASSERT ( IsValid ());
2015-01-18 11:02:17 +01:00
tolua_pushnumber ( m_LuaState , static_cast < lua_Number > ( a_Value . count ()));
2015-01-11 21:12:26 +00:00
m_NumCurrentFunctionArgs += 1 ;
}
2013-08-09 14:58:43 +02:00
2013-08-11 14:57:07 +02:00
2015-05-19 15:25:18 +01:00
bool cLuaState :: GetStackValue ( int a_StackPos , AString & a_Value )
2015-04-23 19:41:01 +02: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 15:25:18 +01:00
return true ;
2015-04-23 19:41:01 +02:00
}
2015-05-19 15:25:18 +01:00
return false ;
2015-04-23 19:41:01 +02:00
}
2015-05-19 15:25:18 +01:00
bool cLuaState :: GetStackValue ( int a_StackPos , bool & a_ReturnedVal )
2013-08-08 14:08:21 +02:00
{
a_ReturnedVal = ( tolua_toboolean ( m_LuaState , a_StackPos , a_ReturnedVal ? 1 : 0 ) > 0 );
2015-05-19 15:25:18 +01:00
return true ;
2013-08-08 14:08:21 +02:00
}
2015-05-19 15:25:18 +01:00
bool cLuaState :: GetStackValue ( int a_StackPos , cPluginManager :: CommandResult & a_Result )
2015-05-10 23:11:30 +02: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 15:25:18 +01:00
return true ;
2015-05-10 23:11:30 +02:00
}
2015-05-19 15:25:18 +01:00
return false ;
2015-05-10 23:11:30 +02:00
}
2015-05-19 15:25:18 +01:00
bool cLuaState :: GetStackValue ( int a_StackPos , cRef & a_Ref )
2013-08-08 14:08:21 +02:00
{
2015-04-23 19:41:01 +02:00
a_Ref . RefStack ( * this , a_StackPos );
2015-05-19 15:25:18 +01:00
return true ;
2013-08-08 14:08:21 +02:00
}
2015-05-19 15:25:18 +01:00
bool cLuaState :: GetStackValue ( int a_StackPos , double & a_ReturnedVal )
2013-08-08 14:08:21 +02:00
{
if ( lua_isnumber ( m_LuaState , a_StackPos ))
{
2015-04-23 19:41:01 +02:00
a_ReturnedVal = tolua_tonumber ( m_LuaState , a_StackPos , a_ReturnedVal );
2015-05-19 15:25:18 +01:00
return true ;
2013-08-09 14:58:43 +02:00
}
2015-05-19 15:25:18 +01:00
return false ;
2013-08-09 14:58:43 +02:00
}
2015-06-17 15:21:20 +02:00
bool cLuaState :: GetStackValue ( int a_StackPos , eBlockFace & a_ReturnedVal )
2015-05-08 23:32:02 +01:00
{
2015-06-17 15:21:20 +02:00
if ( ! lua_isnumber ( m_LuaState , a_StackPos ))
2015-05-08 23:32:02 +01:00
{
2015-06-17 15:21:20 +02:00
return false ;
2015-05-08 23:32:02 +01:00
}
2015-06-17 15:21:20 +02: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 23:32:02 +01:00
}
2015-05-19 15:25:18 +01:00
bool cLuaState :: GetStackValue ( int a_StackPos , eWeather & a_ReturnedVal )
2013-08-09 14:58:43 +02:00
{
2015-04-23 19:41:01 +02:00
if ( ! lua_isnumber ( m_LuaState , a_StackPos ))
2013-08-09 14:58:43 +02:00
{
2015-05-19 15:25:18 +01:00
return false ;
2013-08-08 14:08:21 +02:00
}
2015-04-23 19:41:01 +02: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 15:25:18 +01:00
return true ;
2014-07-03 17:49:21 +02:00
}
2015-06-17 15:21:20 +02: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 15:37:41 +02: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 15:21:20 +02:00
lua_pushvalue ( m_LuaState , - 1 ); // Copy the stack value into the "working area"
2015-06-20 15:37:41 +02:00
auto path = StringSplit ( a_Name , "." );
2015-06-17 15:21:20 +02: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 10:32:42 +01:00
if ( lua_isnil ( m_LuaState , - 1 ))
{
lua_pop ( m_LuaState , 1 );
return cStackValue ();
}
2015-07-21 23:40:13 +01:00
return cStackValue ( * this );
2015-06-17 15:21:20 +02:00
}
2015-11-11 10:32:42 +01: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 22:41:17 +01:00
return cStackValue ( * this );
2015-11-11 10:32:42 +01:00
}
2013-08-06 08:59:54 +02:00
bool cLuaState :: CallFunction ( int a_NumResults )
2013-08-04 23:11:25 +02:00
{
2013-08-06 08:59:54 +02:00
ASSERT ( m_NumCurrentFunctionArgs >= 0 ); // A function must be pushed to stack first
2014-01-11 23:10:40 +01: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 23:45:45 +02:00
2014-02-11 08:52:14 +01: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 23:45:45 +02:00
2014-02-11 08:52:14 +01:00
// Call the function:
int s = lua_pcall ( m_LuaState , NumArgs , a_NumResults , - NumArgs - 2 );
2014-01-11 23:10:40 +01:00
if ( s != 0 )
2013-08-04 23:11:25 +02:00
{
2014-01-11 23:10:40 +01:00
// The error has already been printed together with the stacktrace
2014-02-11 08:52:14 +01:00
LOGWARNING ( "Error in %s calling function %s()" , m_SubsystemName . c_str (), CurrentFunctionName . c_str ());
2013-08-04 23:11:25 +02:00
return false ;
}
2016-02-05 23:45:45 +02:00
2014-01-21 22:59:08 +01:00
// Remove the error handler from the stack:
lua_remove ( m_LuaState , - a_NumResults - 1 );
2016-02-05 23:45:45 +02:00
2013-08-04 23:11:25 +02:00
return true ;
}
2013-11-22 16:49:38 +01:00
bool cLuaState :: CheckParamUserTable ( int a_StartParam , const char * a_UserTable , int a_EndParam )
{
ASSERT ( IsValid ());
2016-02-05 23:45:45 +02:00
2013-11-22 16:49:38 +01:00
if ( a_EndParam < 0 )
{
a_EndParam = a_StartParam ;
}
2016-02-05 23:45:45 +02:00
2013-11-22 16:49:38 +01: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 21:55:07 +01:00
AString ErrMsg = Printf ( "#ferror in function '%s'." , ( entry . name != nullptr ) ? entry . name : "?" );
2013-11-22 16:49:38 +01:00
tolua_error ( m_LuaState , ErrMsg . c_str (), & tolua_err );
return false ;
} // for i - Param
2016-02-05 23:45:45 +02:00
2013-11-22 16:49:38 +01:00
// All params checked ok
return true ;
}
2013-08-07 14:26:18 +02:00
bool cLuaState :: CheckParamUserType ( int a_StartParam , const char * a_UserType , int a_EndParam )
{
ASSERT ( IsValid ());
2016-02-05 23:45:45 +02:00
2013-08-07 14:26:18 +02:00
if ( a_EndParam < 0 )
{
a_EndParam = a_StartParam ;
}
2016-02-05 23:45:45 +02:00
2013-08-07 14:26:18 +02: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 21:55:07 +01:00
AString ErrMsg = Printf ( "#ferror in function '%s'." , ( entry . name != nullptr ) ? entry . name : "?" );
2013-08-07 14:26:18 +02:00
tolua_error ( m_LuaState , ErrMsg . c_str (), & tolua_err );
return false ;
} // for i - Param
2016-02-05 23:45:45 +02:00
2013-08-07 14:26:18 +02:00
// All params checked ok
return true ;
}
bool cLuaState :: CheckParamTable ( int a_StartParam , int a_EndParam )
{
ASSERT ( IsValid ());
2016-02-05 23:45:45 +02:00
2013-08-07 14:26:18 +02:00
if ( a_EndParam < 0 )
{
a_EndParam = a_StartParam ;
}
2016-02-05 23:45:45 +02:00
2013-08-07 14:26:18 +02: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 21:55:07 +01:00
AString ErrMsg = Printf ( "#ferror in function '%s'." , ( entry . name != nullptr ) ? entry . name : "?" );
2015-05-16 16:19:18 +02:00
BreakIntoDebugger ( m_LuaState );
2013-08-07 14:26:18 +02:00
tolua_error ( m_LuaState , ErrMsg . c_str (), & tolua_err );
return false ;
} // for i - Param
2016-02-05 23:45:45 +02:00
2013-08-07 14:26:18 +02:00
// All params checked ok
return true ;
}
bool cLuaState :: CheckParamNumber ( int a_StartParam , int a_EndParam )
{
ASSERT ( IsValid ());
2016-02-05 23:45:45 +02:00
2013-08-07 14:26:18 +02:00
if ( a_EndParam < 0 )
{
a_EndParam = a_StartParam ;
}
2016-02-05 23:45:45 +02:00
2013-08-07 14:26:18 +02: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 21:55:07 +01:00
AString ErrMsg = Printf ( "#ferror in function '%s'." , ( entry . name != nullptr ) ? entry . name : "?" );
2013-08-07 14:26:18 +02:00
tolua_error ( m_LuaState , ErrMsg . c_str (), & tolua_err );
return false ;
} // for i - Param
2016-02-05 23:45:45 +02:00
2013-08-07 14:26:18 +02:00
// All params checked ok
return true ;
}
2015-12-16 15:04:47 +01:00
bool cLuaState :: CheckParamBool ( int a_StartParam , int a_EndParam )
{
ASSERT ( IsValid ());
2016-02-05 23:45:45 +02:00
2015-12-16 15:04:47 +01:00
if ( a_EndParam < 0 )
{
a_EndParam = a_StartParam ;
}
2016-02-05 23:45:45 +02:00
2015-12-16 15:04:47 +01: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 23:45:45 +02:00
2015-12-16 15:04:47 +01:00
// All params checked ok
return true ;
}
2013-11-22 20:11:24 +01:00
bool cLuaState :: CheckParamString ( int a_StartParam , int a_EndParam )
{
ASSERT ( IsValid ());
2016-02-05 23:45:45 +02:00
2013-11-22 20:11:24 +01:00
if ( a_EndParam < 0 )
{
a_EndParam = a_StartParam ;
}
2016-02-05 23:45:45 +02:00
2013-11-22 20:11:24 +01:00
tolua_Error tolua_err ;
for ( int i = a_StartParam ; i <= a_EndParam ; i ++ )
{
2015-09-28 14:53:50 +02:00
if ( lua_isstring ( m_LuaState , i ))
2013-11-22 20:11:24 +01: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 14:53:50 +02:00
tolua_err . array = 0 ;
tolua_err . type = "string" ;
tolua_err . index = i ;
2014-10-20 21:55:07 +01:00
AString ErrMsg = Printf ( "#ferror in function '%s'." , ( entry . name != nullptr ) ? entry . name : "?" );
2013-11-22 20:11:24 +01:00
tolua_error ( m_LuaState , ErrMsg . c_str (), & tolua_err );
return false ;
} // for i - Param
2016-02-05 23:45:45 +02:00
2013-11-22 20:11:24 +01:00
// All params checked ok
return true ;
}
2014-01-19 23:45:26 +01:00
bool cLuaState :: CheckParamFunction ( int a_StartParam , int a_EndParam )
{
ASSERT ( IsValid ());
2016-02-05 23:45:45 +02:00
2014-01-19 23:45:26 +01:00
if ( a_EndParam < 0 )
{
a_EndParam = a_StartParam ;
}
2016-02-05 23:45:45 +02:00
2014-01-19 23:45:26 +01: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 15:03:35 +01:00
luaL_error ( m_LuaState , "Error in function '%s' parameter #%d. Function expected, got %s" ,
2014-10-20 21:55:07 +01:00
( entry . name != nullptr ) ? entry . name : "?" , i , GetTypeText ( i ). c_str ()
2014-02-11 15:03:35 +01:00
);
return false ;
} // for i - Param
2016-02-05 23:45:45 +02:00
2014-02-11 15:03:35 +01:00
// All params checked ok
return true ;
}
bool cLuaState :: CheckParamFunctionOrNil ( int a_StartParam , int a_EndParam )
{
ASSERT ( IsValid ());
2016-02-05 23:45:45 +02:00
2014-02-11 15:03:35 +01:00
if ( a_EndParam < 0 )
{
a_EndParam = a_StartParam ;
}
2016-02-05 23:45:45 +02:00
2014-02-11 15:03:35 +01: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 21:55:07 +01:00
( entry . name != nullptr ) ? entry . name : "?" , i , GetTypeText ( i ). c_str ()
2014-01-19 23:45:26 +01:00
);
return false ;
} // for i - Param
2016-02-05 23:45:45 +02:00
2014-01-19 23:45:26 +01:00
// All params checked ok
return true ;
}
2013-08-07 14:26:18 +02:00
bool cLuaState :: CheckParamEnd ( int a_Param )
{
tolua_Error tolua_err ;
2015-05-08 23:32:02 +01:00
if ( tolua_isnoobj ( m_LuaState , a_Param , & tolua_err ) == 1 )
2013-08-07 14:26:18 +02: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 21:55:07 +01:00
AString ErrMsg = Printf ( "#ferror in function '%s': Too many arguments." , ( entry . name != nullptr ) ? entry . name : "?" );
2013-08-07 14:26:18 +02:00
tolua_error ( m_LuaState , ErrMsg . c_str (), & tolua_err );
return false ;
}
2015-03-21 17:17:26 +00:00
bool cLuaState :: IsParamUserType ( int a_Param , AString a_UserType )
{
ASSERT ( IsValid ());
2016-02-05 23:45:45 +02:00
2015-03-21 17:17:26 +00:00
tolua_Error tolua_err ;
2015-05-08 23:32:02 +01:00
return ( tolua_isusertype ( m_LuaState , a_Param , a_UserType . c_str (), 0 , & tolua_err ) == 1 );
2015-03-21 17:17:26 +00:00
}
bool cLuaState :: IsParamNumber ( int a_Param )
{
ASSERT ( IsValid ());
2016-02-05 23:45:45 +02:00
2015-03-21 17:17:26 +00:00
tolua_Error tolua_err ;
2015-05-08 23:32:02 +01:00
return ( tolua_isnumber ( m_LuaState , a_Param , 0 , & tolua_err ) == 1 );
2015-03-21 17:17:26 +00:00
}
2013-08-04 23:11:25 +02: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 23:45:45 +02:00
2013-08-04 23:11:25 +02:00
LOGWARNING ( "LUA: %d - %s" , a_Status , lua_tostring ( a_LuaState , - 1 ));
lua_pop ( a_LuaState , 1 );
return true ;
}
2013-08-07 14:26:18 +02:00
2014-03-19 22:55:47 +01:00
void cLuaState :: LogStackTrace ( int a_StartingDepth )
2014-01-11 22:51:10 +01:00
{
2014-03-19 22:55:47 +01:00
LogStackTrace ( m_LuaState , a_StartingDepth );
2014-01-11 22:51:10 +01:00
}
2014-03-19 22:55:47 +01:00
void cLuaState :: LogStackTrace ( lua_State * a_LuaState , int a_StartingDepth )
2013-08-21 20:06:37 +02:00
{
LOGWARNING ( "Stack trace:" );
lua_Debug entry ;
2014-03-19 22:55:47 +01:00
int depth = a_StartingDepth ;
2014-01-11 22:51:10 +01:00
while ( lua_getstack ( a_LuaState , depth , & entry ))
2013-08-21 20:06:37 +02:00
{
2014-02-04 22:24:03 +01:00
lua_getinfo ( a_LuaState , "Sln" , & entry );
2014-01-11 22:51:10 +01:00
LOGWARNING ( " %s(%d): %s" , entry . short_src , entry . currentline , entry . name ? entry . name : "(no name)" );
2013-08-21 20:06:37 +02:00
depth ++ ;
}
LOGWARNING ( "Stack trace end" );
}
AString cLuaState :: GetTypeText ( int a_StackPos )
{
2014-01-21 22:59:08 +01: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 23:45:45 +02:00
2014-01-21 22:59:08 +01:00
// Store the stack position before any changes
int OldTop = lua_gettop ( m_LuaState );
2016-02-05 23:45:45 +02:00
2014-01-21 22:59:08 +01: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 23:02:18 +02:00
lua_settop ( m_LuaState , OldTop );
2014-01-21 22:59:08 +01:00
return - 1 ;
}
// Copy the function parameters to the target state
if ( CopyStackFrom ( a_SrcLuaState , a_SrcParamStart , a_SrcParamEnd ) < 0 )
2013-08-21 20:06:37 +02:00
{
2014-01-21 22:59:08 +01:00
// Something went wrong, fix the stack and exit
2015-05-07 23:02:18 +02:00
lua_settop ( m_LuaState , OldTop );
2014-02-04 09:18:32 +01:00
m_NumCurrentFunctionArgs = - 1 ;
m_CurrentFunctionName . clear ();
2014-01-21 22:59:08 +01:00
return - 1 ;
}
2016-02-05 23:45:45 +02:00
2014-01-21 22:59:08 +01:00
// Call the function, with an error handler:
2014-02-04 10:29:10 +01:00
int s = lua_pcall ( m_LuaState , a_SrcParamEnd - a_SrcParamStart + 1 , LUA_MULTRET , OldTop + 1 );
2014-01-21 22:59:08 +01:00
if ( ReportErrors ( s ))
{
LOGWARN ( "Error while calling function '%s' in '%s'" , a_FunctionName . c_str (), m_SubsystemName . c_str ());
2015-05-07 23:02:18 +02:00
// Reset the stack:
lua_settop ( m_LuaState , OldTop );
2016-02-05 23:45:45 +02:00
2014-02-04 09:18:32 +01:00
// Reset the internal checking mechanisms:
m_NumCurrentFunctionArgs = - 1 ;
m_CurrentFunctionName . clear ();
2016-02-05 23:45:45 +02:00
2014-02-04 10:29:10 +01: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 20:06:37 +02:00
}
2016-02-05 23:45:45 +02:00
2014-01-21 22:59:08 +01:00
// Reset the internal checking mechanisms:
m_NumCurrentFunctionArgs = - 1 ;
2014-02-04 09:18:32 +01:00
m_CurrentFunctionName . clear ();
2016-02-05 23:45:45 +02:00
2014-01-21 22:59:08 +01:00
// Remove the error handler from the stack:
lua_remove ( m_LuaState , OldTop + 1 );
2016-02-05 23:45:45 +02:00
2014-01-21 22:59:08 +01:00
// 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 21:55:07 +01:00
const char * type = nullptr ;
2014-01-21 22:59:08 +01: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
2016-02-05 23:45:45 +02:00
2014-01-21 22:59:08 +01:00
// Copy the value:
2014-10-20 21:55:07 +01:00
void * ud = tolua_touserdata ( a_SrcLuaState , i , nullptr );
2014-01-21 22:59:08 +01:00
tolua_pushusertype ( m_LuaState , ud , type );
2014-02-04 14:26:36 +01:00
break ;
2014-01-21 22:59:08 +01: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
);
2016-03-21 09:58:15 +01:00
a_SrcLuaState . LogStack ( "Stack where copying failed:" );
2014-01-21 22:59:08 +01:00
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 21:55:07 +01:00
if ( s != nullptr )
2014-01-21 22:59:08 +01:00
{
a_String . assign ( s , len );
}
}
2016-03-21 09:58:15 +01:00
void cLuaState :: LogStack ( const char * a_Header )
2014-01-21 22:59:08 +01:00
{
2016-03-21 09:58:15 +01:00
LogStack ( m_LuaState , a_Header );
2014-01-21 22:59:08 +01:00
}
2016-03-21 09:58:15 +01:00
void cLuaState :: LogStack ( lua_State * a_LuaState , const char * a_Header )
2014-01-21 22:59:08 +01:00
{
2014-03-11 14:16:08 -07:00
// Format string consisting only of %s is used to appease the compiler
2014-10-20 21:55:07 +01:00
LOG ( "%s" , ( a_Header != nullptr ) ? a_Header : "Lua C API Stack contents:" );
2014-02-10 22:44:56 +01:00
for ( int i = lua_gettop ( a_LuaState ); i > 0 ; i -- )
2014-01-21 22:59:08 +01: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 09:04:03 -06:00
case LUA_TNUMBER : Printf ( Value , "%f" , static_cast < double > ( lua_tonumber ( a_LuaState , i ))); break ;
2014-01-21 22:59:08 +01:00
case LUA_TSTRING : Printf ( Value , "%s" , lua_tostring ( a_LuaState , i )); break ;
2014-02-17 23:12:46 +01:00
case LUA_TTABLE : Printf ( Value , "%p" , lua_topointer ( a_LuaState , i )); break ;
2014-01-21 22:59:08 +01: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 20:06:37 +02:00
}
2014-01-11 23:10:40 +01:00
int cLuaState :: ReportFnCallErrors ( lua_State * a_LuaState )
{
LOGWARNING ( "LUA: %s" , lua_tostring ( a_LuaState , - 1 ));
2014-03-19 22:55:47 +01:00
LogStackTrace ( a_LuaState , 1 );
2015-05-16 16:19:18 +02:00
BreakIntoDebugger ( a_LuaState );
2014-01-11 23:10:40 +01:00
return 1 ; // We left the error message on the stack as the return value
}
2015-05-16 16:19:18 +02: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 22:15:34 +02:00
////////////////////////////////////////////////////////////////////////////////
2013-08-07 14:26:18 +02:00
// cLuaState::cRef:
2014-02-09 18:39:22 +01:00
cLuaState :: cRef :: cRef ( void ) :
2014-10-20 21:55:07 +01:00
m_LuaState ( nullptr ),
2014-02-09 18:39:22 +01:00
m_Ref ( LUA_REFNIL )
{
}
2013-08-07 14:26:18 +02:00
cLuaState :: cRef :: cRef ( cLuaState & a_LuaState , int a_StackPos ) :
2014-10-20 21:55:07 +01:00
m_LuaState ( nullptr ),
2014-02-09 18:39:22 +01:00
m_Ref ( LUA_REFNIL )
2013-08-07 14:26:18 +02:00
{
2014-02-09 18:39:22 +01:00
RefStack ( a_LuaState , a_StackPos );
2013-08-07 14:26:18 +02:00
}
2015-01-30 21:24:02 +01: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 14:26:18 +02:00
cLuaState :: cRef ::~ cRef ()
{
2014-10-20 21:55:07 +01:00
if ( m_LuaState != nullptr )
2014-02-09 18:39:22 +01:00
{
UnRef ();
}
}
void cLuaState :: cRef :: RefStack ( cLuaState & a_LuaState , int a_StackPos )
{
ASSERT ( a_LuaState . IsValid ());
2014-10-20 21:55:07 +01:00
if ( m_LuaState != nullptr )
2014-02-09 18:39:22 +01:00
{
UnRef ();
}
2016-03-21 09:58:15 +01:00
m_LuaState = & a_LuaState ;
2014-02-09 18:39:22 +01: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 )
{
2016-03-21 09:58:15 +01:00
ASSERT ( m_LuaState -> IsValid ()); // The reference should be destroyed before destroying the LuaState
2013-08-07 14:26:18 +02:00
if ( IsValid ())
{
2016-03-21 09:58:15 +01:00
luaL_unref ( * m_LuaState , LUA_REGISTRYINDEX , m_Ref );
2013-08-07 14:26:18 +02:00
}
2014-10-20 21:55:07 +01:00
m_LuaState = nullptr ;
2014-02-09 18:39:22 +01:00
m_Ref = LUA_REFNIL ;
2013-08-07 14:26:18 +02:00
}