mirror of
https://github.com/nillerusr/source-engine.git
synced 2025-03-13 05:02:54 +00:00
1503 lines
34 KiB
C++
1503 lines
34 KiB
C++
//========== Copyright <20> 2008, Valve Corporation, All rights reserved. ========
|
||
//
|
||
// Purpose:
|
||
//
|
||
//=============================================================================
|
||
|
||
#include <stdio.h>
|
||
#if defined(POSIX)
|
||
#include <curses.h>
|
||
#include <unistd.h>
|
||
#else
|
||
#include <io.h>
|
||
#include <conio.h>
|
||
#include <direct.h>
|
||
#endif
|
||
|
||
#include "platform.h"
|
||
|
||
#if !defined(OSX) && !defined(POSIX)
|
||
extern "C"
|
||
{
|
||
#endif
|
||
#include "lua.h"
|
||
#include "lauxlib.h"
|
||
#include "lualib.h"
|
||
#ifdef getstr // Already defined in curses.h on linux
|
||
#undef getstr
|
||
#endif
|
||
#include "lobject.h"
|
||
#include "lstate.h"
|
||
#include "ldo.h"
|
||
#if !defined(OSX) && !defined(POSIX)
|
||
}
|
||
#endif
|
||
|
||
#include "vec3.h"
|
||
|
||
#include "tier1/utlmap.h"
|
||
|
||
#include "datamap.h"
|
||
#include "tier1/functors.h"
|
||
#include "tier1/utlvector.h"
|
||
#include "tier1/utlhash.h"
|
||
#include "tier1/utlbuffer.h"
|
||
#include "tier1/fmtstr.h"
|
||
#include "tier1/convar.h"
|
||
#include "mathlib/vector.h"
|
||
#include "vstdlib/random.h"
|
||
|
||
#include "vscript/ivscript.h"
|
||
|
||
#include <string>
|
||
|
||
//#include "init_nut.h"
|
||
|
||
#include "memdbgon.h"
|
||
|
||
#ifdef VLUA_DEBUG_SERIALIZATION
|
||
static int lastType;
|
||
#endif
|
||
|
||
|
||
//-------------------------------------------------------------------------
|
||
// Helpers
|
||
//-------------------------------------------------------------------------
|
||
|
||
static const char *FieldTypeToString( int type )
|
||
{
|
||
switch( type )
|
||
{
|
||
case FIELD_VOID: return "void";
|
||
case FIELD_FLOAT: return "float";
|
||
case FIELD_CSTRING: return "string";
|
||
case FIELD_VECTOR: return "Vector";
|
||
case FIELD_INTEGER: return "int";
|
||
case FIELD_BOOLEAN: return "bool";
|
||
case FIELD_CHARACTER: return "char";
|
||
case FIELD_HSCRIPT: return "handle";
|
||
default: return "<unknown>";
|
||
}
|
||
}
|
||
|
||
|
||
static const char *LUATypeToString( int nLUAType )
|
||
{
|
||
switch( nLUAType )
|
||
{
|
||
case LUA_TNUMBER: return "FLOAT";
|
||
case LUA_TBOOLEAN: return "BOOL";
|
||
case LUA_TSTRING: return "STRING";
|
||
case LUA_TNIL: return "NULL";
|
||
case LUA_TTABLE: return "TABLE";
|
||
case LUA_TUSERDATA: return "USERDATA";
|
||
case LUA_TTHREAD: return "THREAD";
|
||
}
|
||
return "<unknown>";
|
||
}
|
||
|
||
|
||
class CLuaVM : public IScriptVM
|
||
{
|
||
lua_State *m_LuaState;
|
||
ScriptOutputFunc_t m_OutputFunc;
|
||
ScriptErrorFunc_t m_ErrorFunc;
|
||
int64 m_iUniqueIdSerialNumber;
|
||
|
||
// CUtlHashFast<SQClass *, CUtlHashFastGenericHash> m_TypeMap;
|
||
|
||
struct InstanceContext_t
|
||
{
|
||
void *pInstance;
|
||
ScriptClassDesc_t *pClassDesc;
|
||
char szName[ 64 ];
|
||
};
|
||
|
||
|
||
public:
|
||
CLuaVM( lua_State *pState = NULL )
|
||
{
|
||
m_LuaState = pState;
|
||
m_iUniqueIdSerialNumber = 0;
|
||
|
||
m_OutputFunc = NULL;
|
||
m_ErrorFunc = NULL;
|
||
|
||
// m_TypeMap.Init( 256 );
|
||
}
|
||
|
||
static int PrintFunc( lua_State *pState )
|
||
{
|
||
ScriptOutputFunc_t m_OutputFunc = *( ( ScriptOutputFunc_t * )lua_touserdata( pState, lua_upvalueindex( 1 ) ) );
|
||
CUtlString Output;
|
||
|
||
int n = lua_gettop( pState ); /* number of arguments */
|
||
int i;
|
||
lua_getglobal( pState, "towstring" );
|
||
lua_getglobal( pState, "tostring" );
|
||
for ( i=1; i <= n; i++ )
|
||
{
|
||
const char *s = NULL;
|
||
lua_pushvalue( pState, -1 ); /* function to be called */
|
||
lua_pushvalue( pState, i ); /* value to print */
|
||
lua_call( pState, 1, 1 );
|
||
s = lua_tostring( pState, -1 ); /* get result */
|
||
if ( s == NULL )
|
||
{
|
||
return luaL_error( pState, LUA_QL( "tostring" ) " must return a string to " LUA_QL( "print" ) );
|
||
}
|
||
if ( i > 1 )
|
||
{
|
||
Output += "\t";
|
||
}
|
||
if ( s )
|
||
{
|
||
Output += s;
|
||
}
|
||
lua_pop( pState, 1 ); /* pop result */
|
||
}
|
||
|
||
if ( m_OutputFunc )
|
||
{
|
||
m_OutputFunc( Output );
|
||
}
|
||
else
|
||
{
|
||
Msg( "%s\n", Output.Get() );
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
void HandleError( const char *pszErrorText )
|
||
{
|
||
if ( m_ErrorFunc )
|
||
{
|
||
m_ErrorFunc( SCRIPT_LEVEL_WARNING, pszErrorText );
|
||
}
|
||
else
|
||
{
|
||
Msg( pszErrorText );
|
||
}
|
||
}
|
||
|
||
static int FatalErrorHandler( lua_State *pState )
|
||
{
|
||
const char *err = lua_tostring( pState, 1 );
|
||
|
||
throw( err );
|
||
}
|
||
|
||
void FatalError( const char *pszError )
|
||
{
|
||
if ( m_ErrorFunc )
|
||
{
|
||
m_ErrorFunc( SCRIPT_LEVEL_ERROR, pszError );
|
||
}
|
||
else
|
||
{
|
||
Msg( pszError );
|
||
}
|
||
}
|
||
|
||
int GetStackSize( )
|
||
{
|
||
return ( ( char * )m_LuaState->stack_last - ( char * )m_LuaState->top ) / sizeof( TValue );
|
||
}
|
||
|
||
static void stackDump (lua_State *L)
|
||
{
|
||
int i;
|
||
int top = lua_gettop(L);
|
||
for (i = 1; i <= top; i++) { /* repeat for each level */
|
||
int t = lua_type(L, i);
|
||
switch (t) {
|
||
|
||
case LUA_TSTRING: /* strings */
|
||
printf("`%s'", lua_tostring(L, i));
|
||
break;
|
||
|
||
case LUA_TBOOLEAN: /* booleans */
|
||
printf(lua_toboolean(L, i) ? "true" : "false");
|
||
break;
|
||
|
||
case LUA_TNUMBER: /* numbers */
|
||
printf("%g", lua_tonumber(L, i));
|
||
break;
|
||
|
||
default: /* other values */
|
||
printf("%s", lua_typename(L, t));
|
||
break;
|
||
|
||
}
|
||
printf(" "); /* put a separator */
|
||
}
|
||
printf("\n"); /* end the listing */
|
||
}
|
||
|
||
//-------------------------------------------------------------
|
||
//
|
||
//-------------------------------------------------------------
|
||
static void PushVariant( lua_State *pState, const ScriptVariant_t &value )
|
||
{
|
||
switch ( value.m_type )
|
||
{
|
||
case FIELD_VOID:
|
||
lua_pushnil( pState );
|
||
break;
|
||
|
||
case FIELD_FLOAT:
|
||
lua_pushnumber( pState, value.m_float );
|
||
break;
|
||
|
||
case FIELD_CSTRING:
|
||
lua_pushstring( pState, value );
|
||
break;
|
||
|
||
case FIELD_VECTOR:
|
||
lua_newvec3( pState, value.m_pVector );
|
||
break;
|
||
|
||
case FIELD_INTEGER:
|
||
lua_pushinteger( pState, value.m_int );
|
||
break;
|
||
|
||
case FIELD_BOOLEAN:
|
||
lua_pushboolean( pState, value.m_bool );
|
||
break;
|
||
|
||
case FIELD_CHARACTER:
|
||
{
|
||
char sz[2];
|
||
|
||
sz[0] = value.m_char;
|
||
sz[1] = 0;
|
||
lua_pushlstring( pState, sz, 1 );
|
||
break;
|
||
}
|
||
|
||
case FIELD_HSCRIPT:
|
||
if ( value.m_hScript == NULL )
|
||
{
|
||
lua_pushnil( pState );
|
||
}
|
||
else
|
||
{
|
||
lua_rawgeti( pState, LUA_REGISTRYINDEX, size_cast< int > ( ( intp )value.m_hScript ) );
|
||
Assert( lua_isnil( pState, -1 ) == false );
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
//-------------------------------------------------------------
|
||
//
|
||
//-------------------------------------------------------------
|
||
static bool ConvertToVariant( int nStackIndex, lua_State *pState, ScriptVariant_t *pReturn )
|
||
{
|
||
switch ( lua_type( pState, nStackIndex ) )
|
||
{
|
||
case LUA_TNIL:
|
||
pReturn->m_type = FIELD_VOID;
|
||
break;
|
||
case LUA_TNUMBER:
|
||
*pReturn = ( float )lua_tonumber( pState, nStackIndex );
|
||
break;
|
||
case LUA_TBOOLEAN:
|
||
*pReturn = ( lua_toboolean( pState, nStackIndex ) != 0 );
|
||
break;
|
||
case LUA_TSTRING:
|
||
{
|
||
int size = strlen( lua_tostring( pState, nStackIndex ) ) + 1;
|
||
pReturn->m_type = FIELD_CSTRING;
|
||
pReturn->m_pszString = new char[ size ];
|
||
memcpy( (void *)pReturn->m_pszString, lua_tostring( pState, nStackIndex ), size );
|
||
pReturn->m_flags |= SV_FREE;
|
||
}
|
||
break;
|
||
#if 0
|
||
case OT_INSTANCE:
|
||
{
|
||
SQUserPointer pVector;
|
||
sq_pushobject( m_hVM, object );
|
||
SQRESULT getResult = sq_getinstanceup( m_hVM, -1, &pVector, TYPETAG_VECTOR );
|
||
sq_poptop( m_hVM );
|
||
if ( getResult == SQ_OK )
|
||
{
|
||
pReturn->m_type = FIELD_VECTOR;
|
||
pReturn->m_pVector = new Vector( *((Vector *)pVector) );
|
||
pReturn->m_flags |= SV_FREE;
|
||
break;
|
||
}
|
||
}
|
||
// fall through
|
||
#endif
|
||
default:
|
||
{
|
||
Assert( nStackIndex == -1 );
|
||
pReturn->m_type = FIELD_HSCRIPT;
|
||
pReturn->m_hScript = ( HSCRIPT )( intp )luaL_ref( pState, LUA_REGISTRYINDEX );
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
static void ReleaseVariant( lua_State *pState, ScriptVariant_t &value )
|
||
{
|
||
if ( value.m_type == FIELD_HSCRIPT )
|
||
{
|
||
luaL_unref( pState, LUA_REGISTRYINDEX, size_cast< int >( ( intp )value.m_hScript ) );
|
||
}
|
||
else
|
||
{
|
||
value.Free();
|
||
}
|
||
value.m_type = FIELD_VOID;
|
||
}
|
||
|
||
virtual bool Init( )
|
||
{
|
||
m_LuaState = luaL_newstate();
|
||
luaL_openlibs( m_LuaState );
|
||
luaopen_vec3( m_LuaState );
|
||
|
||
lua_atpanic( m_LuaState, FatalErrorHandler );
|
||
|
||
SetOutputCallback( NULL );
|
||
|
||
return true;
|
||
}
|
||
|
||
virtual void Shutdown()
|
||
{
|
||
if ( m_LuaState )
|
||
{
|
||
lua_close( m_LuaState );
|
||
m_LuaState = NULL;
|
||
}
|
||
|
||
// m_TypeMap.Purge();
|
||
}
|
||
|
||
virtual bool ConnectDebugger()
|
||
{
|
||
Assert( 0 );
|
||
return false;
|
||
}
|
||
|
||
virtual void DisconnectDebugger()
|
||
{
|
||
Assert( 0 );
|
||
}
|
||
|
||
virtual ScriptLanguage_t GetLanguage()
|
||
{
|
||
return SL_LUA;
|
||
}
|
||
|
||
virtual const char *GetLanguageName()
|
||
{
|
||
return "Lua";
|
||
}
|
||
|
||
virtual void AddSearchPath( const char *pszSearchPath )
|
||
{
|
||
lua_getfield( m_LuaState, LUA_GLOBALSINDEX, "package" );
|
||
if ( !lua_istable( m_LuaState, -1 ) )
|
||
{
|
||
Assert( 0 );
|
||
lua_pop( m_LuaState, 1 );
|
||
return;
|
||
}
|
||
|
||
lua_getfield( m_LuaState, -1, "path" );
|
||
if ( !lua_isstring( m_LuaState, -1 ) )
|
||
{
|
||
Assert( 0 );
|
||
lua_pop( m_LuaState, 1 );
|
||
return;
|
||
}
|
||
|
||
CUtlString szNewPath;
|
||
|
||
szNewPath = lua_tostring( m_LuaState, -1 );
|
||
szNewPath += ";";
|
||
szNewPath += pszSearchPath;
|
||
szNewPath += "\\?.lua";
|
||
|
||
lua_pushstring( m_LuaState, szNewPath );
|
||
lua_setfield( m_LuaState, -3, "path" );
|
||
|
||
lua_pop( m_LuaState, 2 );
|
||
}
|
||
|
||
virtual bool Frame( float simTime )
|
||
{
|
||
if ( m_LuaState )
|
||
{
|
||
Msg( "Garbage Collecting...\n" );
|
||
lua_gc( m_LuaState, LUA_GCCOLLECT, 0 );
|
||
}
|
||
|
||
#if 0
|
||
if ( m_hDbg )
|
||
{
|
||
sq_rdbg_update( m_hDbg );
|
||
if ( !m_hDbg->IsConnected() )
|
||
DisconnectDebugger();
|
||
}
|
||
#endif
|
||
|
||
return true;
|
||
}
|
||
|
||
virtual ScriptStatus_t Run( const char *pszScript, bool bWait = true )
|
||
{
|
||
Assert( 0 );
|
||
return SCRIPT_ERROR;
|
||
}
|
||
|
||
virtual HSCRIPT CompileScript( const char *pszScript, const char *pszId = NULL )
|
||
{
|
||
int nResult = luaL_loadbuffer( m_LuaState, pszScript, strlen( pszScript ), pszId );
|
||
|
||
if ( nResult == 0 )
|
||
{
|
||
int func_ref = luaL_ref( m_LuaState, LUA_REGISTRYINDEX );
|
||
|
||
// lua_rawgeti( m_LuaState, LUA_REGISTRYINDEX, func_ref );
|
||
// lua_call( m_LuaState, 0, 0 );
|
||
|
||
return ( HSCRIPT )( intp )func_ref;
|
||
}
|
||
else
|
||
{
|
||
const char *pszErrorText = lua_tostring( m_LuaState, -1 );
|
||
HandleError( pszErrorText );
|
||
}
|
||
|
||
return INVALID_HSCRIPT;
|
||
}
|
||
|
||
virtual void ReleaseScript( HSCRIPT hScript)
|
||
{
|
||
luaL_unref( m_LuaState, LUA_REGISTRYINDEX, size_cast< int > ( ( intp )hScript ) );
|
||
}
|
||
|
||
virtual ScriptStatus_t Run( HSCRIPT hScript, HSCRIPT hScope = NULL, bool bWait = true )
|
||
{
|
||
lua_rawgeti( m_LuaState, LUA_REGISTRYINDEX, size_cast< int >( ( intp )hScript ) );
|
||
int nResult = lua_pcall( m_LuaState, 0, LUA_MULTRET, 0 );
|
||
|
||
switch( nResult )
|
||
{
|
||
case LUA_ERRRUN:
|
||
{
|
||
const char *pszErrorText = lua_tostring( m_LuaState, -1 );
|
||
HandleError( pszErrorText );
|
||
return SCRIPT_ERROR;
|
||
}
|
||
|
||
case LUA_ERRMEM:
|
||
{
|
||
const char *pszErrorText = lua_tostring( m_LuaState, -1 );
|
||
HandleError( pszErrorText );
|
||
return SCRIPT_ERROR;
|
||
}
|
||
|
||
case LUA_ERRERR:
|
||
{
|
||
const char *pszErrorText = lua_tostring( m_LuaState, -1 );
|
||
HandleError( pszErrorText );
|
||
return SCRIPT_ERROR;
|
||
}
|
||
}
|
||
|
||
return SCRIPT_DONE;
|
||
}
|
||
|
||
virtual ScriptStatus_t Run( HSCRIPT hScript, bool bWait )
|
||
{
|
||
Assert( 0 );
|
||
return SCRIPT_ERROR;
|
||
}
|
||
|
||
// stack good
|
||
virtual HSCRIPT CreateScope( const char *pszScope, HSCRIPT hParent = NULL )
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
virtual void ReleaseScope( HSCRIPT hScript )
|
||
{
|
||
}
|
||
|
||
// stack good
|
||
virtual HSCRIPT LookupFunction( const char *pszFunction, HSCRIPT hScope = NULL )
|
||
{
|
||
if ( hScope )
|
||
{
|
||
lua_rawgeti( m_LuaState, LUA_REGISTRYINDEX, size_cast< int >( ( intp )hScope ) );
|
||
if ( lua_isnil( m_LuaState, -1 ) )
|
||
{
|
||
Assert( 0 );
|
||
lua_pop( m_LuaState, 1 );
|
||
return NULL;
|
||
}
|
||
|
||
lua_getfield( m_LuaState, -1, pszFunction );
|
||
if ( lua_isnil( m_LuaState, -1 ) || !lua_isfunction( m_LuaState, -1 ) )
|
||
{
|
||
lua_pop( m_LuaState, 2 );
|
||
return NULL;
|
||
}
|
||
|
||
int func_ref = luaL_ref( m_LuaState, LUA_REGISTRYINDEX );
|
||
lua_pop( m_LuaState, 1 );
|
||
|
||
return ( HSCRIPT )( intp )func_ref;
|
||
}
|
||
else
|
||
{
|
||
lua_getfield( m_LuaState, LUA_GLOBALSINDEX, pszFunction );
|
||
if ( lua_isnil( m_LuaState, -1 ) || !lua_isfunction( m_LuaState, -1 ) )
|
||
{
|
||
lua_pop( m_LuaState, 1 );
|
||
return NULL;
|
||
}
|
||
|
||
int func_ref = luaL_ref( m_LuaState, LUA_REGISTRYINDEX );
|
||
|
||
return ( HSCRIPT )( intp )func_ref;
|
||
}
|
||
}
|
||
|
||
// stack good
|
||
virtual void ReleaseFunction( HSCRIPT hScript )
|
||
{
|
||
luaL_unref( m_LuaState, LUA_REGISTRYINDEX, size_cast<int>( ( intp )hScript ) );
|
||
}
|
||
|
||
// stack good
|
||
virtual ScriptStatus_t ExecuteFunction( HSCRIPT hFunction, ScriptVariant_t *pArgs, int nArgs, ScriptVariant_t *pReturn, HSCRIPT hScope, bool bWait )
|
||
{
|
||
if ( hScope == INVALID_HSCRIPT )
|
||
{
|
||
DevWarning( "ExecuteFunction: Invalid scope handed to script VM\n" );
|
||
return SCRIPT_ERROR;
|
||
}
|
||
|
||
#if 0
|
||
if ( m_hDbg )
|
||
{
|
||
extern bool g_bSqDbgTerminateScript;
|
||
if ( g_bSqDbgTerminateScript )
|
||
{
|
||
DisconnectDebugger();
|
||
g_bSqDbgTerminateScript = false;
|
||
}
|
||
}
|
||
#endif
|
||
|
||
Assert( bWait );
|
||
|
||
try
|
||
{
|
||
if ( hFunction )
|
||
{
|
||
int nStackSize = GetStackSize();
|
||
|
||
lua_rawgeti( m_LuaState, LUA_REGISTRYINDEX, size_cast< int >( ( intp )hFunction ) );
|
||
|
||
int nTopStack = lua_gettop( m_LuaState );
|
||
|
||
if ( hScope )
|
||
{
|
||
lua_rawgeti( m_LuaState, LUA_REGISTRYINDEX, size_cast< int >( ( intp )hScope ) );
|
||
}
|
||
|
||
for ( int i = 0; i < nArgs; i++ )
|
||
{
|
||
PushVariant( m_LuaState, pArgs[i] );
|
||
}
|
||
|
||
lua_call( m_LuaState, lua_gettop( m_LuaState ) - nTopStack, ( pReturn ? 1 : 0 ) );
|
||
if ( pReturn )
|
||
{
|
||
ConvertToVariant( -1, m_LuaState, pReturn );
|
||
}
|
||
|
||
lua_pop( m_LuaState, nStackSize - GetStackSize() );
|
||
|
||
return SCRIPT_DONE;
|
||
}
|
||
|
||
if ( pReturn )
|
||
{
|
||
pReturn->m_type = FIELD_VOID;
|
||
}
|
||
}
|
||
catch( const char *pszString )
|
||
{
|
||
FatalError( pszString );
|
||
}
|
||
|
||
return SCRIPT_ERROR;
|
||
}
|
||
|
||
// stack good
|
||
static int TranslateCall( lua_State *pState )
|
||
{
|
||
int nActualParams = lua_gettop( pState );
|
||
ScriptFunctionBinding_t *pVMScriptFunction = ( ScriptFunctionBinding_t * )lua_touserdata( pState, lua_upvalueindex( 1 ) );
|
||
int nFormalParams = pVMScriptFunction->m_desc.m_Parameters.Count();
|
||
CUtlVectorFixed<ScriptVariant_t, 14> params;
|
||
ScriptVariant_t returnValue;
|
||
bool bCallFree = false;
|
||
|
||
params.SetSize( nFormalParams );
|
||
|
||
void *pObject = NULL;
|
||
|
||
if ( nActualParams )
|
||
{
|
||
int nOffset = 1;
|
||
|
||
if ( ( pVMScriptFunction->m_flags & SF_MEMBER_FUNC ) )
|
||
{
|
||
InstanceContext_t *pInstanceContext = ( InstanceContext_t * )lua_touserdata( pState, nOffset );
|
||
pObject = pInstanceContext->pInstance;
|
||
|
||
if ( pInstanceContext->pClassDesc->pHelper )
|
||
{
|
||
pObject = pInstanceContext->pClassDesc->pHelper->GetProxied( pObject );
|
||
}
|
||
|
||
if ( !pObject )
|
||
{
|
||
// sq_throwerror( hVM, "Accessed null instance" );
|
||
return SCRIPT_ERROR;
|
||
}
|
||
|
||
nOffset++;
|
||
nActualParams--;
|
||
}
|
||
|
||
int iLimit = ( nActualParams < nFormalParams ? nActualParams : nFormalParams );
|
||
ScriptDataType_t *pCurParamType = pVMScriptFunction->m_desc.m_Parameters.Base();
|
||
|
||
for ( int i = 0; i < iLimit; i++, pCurParamType++ )
|
||
{
|
||
switch ( *pCurParamType )
|
||
{
|
||
case FIELD_FLOAT:
|
||
params[ i ] = ( float )lua_tonumber( pState, i + nOffset );
|
||
break;
|
||
|
||
case FIELD_CSTRING:
|
||
params[ i ] = lua_tostring( pState, i + nOffset );
|
||
break;
|
||
|
||
case FIELD_VECTOR:
|
||
{
|
||
params[ i ] = lua_getvec3( pState, i + nOffset );
|
||
break;
|
||
}
|
||
|
||
case FIELD_INTEGER:
|
||
params[ i ] = ( int )lua_tonumber( pState, i + nOffset );
|
||
break;
|
||
|
||
case FIELD_BOOLEAN:
|
||
params[ i ] = ( lua_toboolean( pState, i + nOffset ) != 0 );
|
||
break;
|
||
|
||
case FIELD_CHARACTER:
|
||
params[ i ] = lua_tostring( pState, i + nOffset )[0];
|
||
break;
|
||
|
||
case FIELD_HSCRIPT:
|
||
{
|
||
lua_pushvalue( pState, i + nOffset );
|
||
params[ i ] = ( HSCRIPT )( intp )luaL_ref( pState, LUA_REGISTRYINDEX );
|
||
// params[ i ].m_flags |= SV_FREE;
|
||
bCallFree = true;
|
||
break;
|
||
}
|
||
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
(*pVMScriptFunction->m_pfnBinding)( pVMScriptFunction->m_pFunction, pObject, params.Base(), params.Count(), ( pVMScriptFunction->m_desc.m_ReturnType != FIELD_VOID ) ? &returnValue : NULL );
|
||
|
||
if ( pVMScriptFunction->m_desc.m_ReturnType != FIELD_VOID )
|
||
{
|
||
PushVariant( pState, returnValue );
|
||
}
|
||
|
||
if ( bCallFree )
|
||
{
|
||
for ( int i = 0; i < params.Count(); i++ )
|
||
{
|
||
ReleaseVariant( pState, params[ i ] );
|
||
// params[i].Free();
|
||
}
|
||
}
|
||
|
||
return ( ( pVMScriptFunction->m_desc.m_ReturnType != FIELD_VOID ) ? 1 : 0 ) ;
|
||
}
|
||
|
||
//-------------------------------------------------------------
|
||
//
|
||
//-------------------------------------------------------------
|
||
// stack good
|
||
void RegisterFunctionGuts( ScriptFunctionBinding_t *pScriptFunction, HSCRIPT pOwningClass = NULL )
|
||
{
|
||
char szTypeMask[ 64 ];
|
||
|
||
if ( pScriptFunction->m_desc.m_Parameters.Count() > ARRAYSIZE(szTypeMask) - 1 )
|
||
{
|
||
AssertMsg1( 0, "Too many agruments for script function %s\n", pScriptFunction->m_desc.m_pszFunction );
|
||
return;
|
||
}
|
||
|
||
szTypeMask[0] = '.';
|
||
char *pCurrent = &szTypeMask[1];
|
||
for ( int i = 0; i < pScriptFunction->m_desc.m_Parameters.Count(); i++, pCurrent++ )
|
||
{
|
||
switch ( pScriptFunction->m_desc.m_Parameters[i] )
|
||
{
|
||
case FIELD_CSTRING:
|
||
*pCurrent = 's';
|
||
break;
|
||
case FIELD_FLOAT:
|
||
case FIELD_INTEGER:
|
||
*pCurrent = 'n';
|
||
break;
|
||
case FIELD_BOOLEAN:
|
||
*pCurrent = 'b';
|
||
break;
|
||
|
||
case FIELD_VECTOR:
|
||
*pCurrent = 'x';
|
||
break;
|
||
|
||
case FIELD_HSCRIPT:
|
||
*pCurrent = '.';
|
||
break;
|
||
|
||
case FIELD_CHARACTER:
|
||
default:
|
||
*pCurrent = FIELD_VOID;
|
||
AssertMsg( 0 , "Not supported" );
|
||
break;
|
||
}
|
||
}
|
||
|
||
int nStackIndex = LUA_GLOBALSINDEX;
|
||
if ( pOwningClass )
|
||
{
|
||
lua_rawgeti( m_LuaState, LUA_REGISTRYINDEX, size_cast< int >( ( intp )pOwningClass ) );
|
||
if ( !lua_isnil( m_LuaState, -1 ) )
|
||
{
|
||
nStackIndex = lua_gettop( m_LuaState );
|
||
}
|
||
}
|
||
|
||
Assert( pCurrent - szTypeMask < ARRAYSIZE(szTypeMask) - 1 );
|
||
*pCurrent = 0;
|
||
lua_pushstring( m_LuaState, pScriptFunction->m_desc.m_pszScriptName );
|
||
lua_pushlightuserdata( m_LuaState, pScriptFunction );
|
||
lua_pushcclosure( m_LuaState, &TranslateCall, 1 );
|
||
lua_settable( m_LuaState, nStackIndex );
|
||
|
||
if ( pOwningClass )
|
||
{
|
||
lua_pop( m_LuaState, 1 );
|
||
}
|
||
|
||
if ( nStackIndex == LUA_GLOBALSINDEX )
|
||
{
|
||
Msg( "VLua: Registered GLOBAL function %s\n", pScriptFunction->m_desc.m_pszScriptName );
|
||
}
|
||
else
|
||
{
|
||
Msg( "VLua: Registered TABLE function %s\n", pScriptFunction->m_desc.m_pszScriptName );
|
||
}
|
||
|
||
#if 0
|
||
if ( developer.GetInt() )
|
||
{
|
||
const char *pszHide = SCRIPT_HIDE;
|
||
if ( !pScriptFunction->m_desc.m_pszDescription || *pScriptFunction->m_desc.m_pszDescription != *pszHide )
|
||
{
|
||
std::string name;
|
||
std::string signature;
|
||
|
||
if ( pClassDesc )
|
||
{
|
||
name += pClassDesc->m_pszScriptName;
|
||
name += "::";
|
||
}
|
||
|
||
name += pScriptFunction->m_desc.m_pszScriptName;
|
||
|
||
signature += FieldTypeToString( pScriptFunction->m_desc.m_ReturnType );
|
||
signature += ' ';
|
||
signature += name;
|
||
signature += '(';
|
||
for ( int i = 0; i < pScriptFunction->m_desc.m_Parameters.Count(); i++ )
|
||
{
|
||
if ( i != 0 )
|
||
{
|
||
signature += ", ";
|
||
}
|
||
|
||
signature+= FieldTypeToString( pScriptFunction->m_desc.m_Parameters[i] );
|
||
}
|
||
signature += ')';
|
||
|
||
sq_pushobject( m_hVM, LookupObject( "RegisterFunctionDocumentation", NULL, false ) );
|
||
sq_pushroottable( m_hVM );
|
||
sq_pushobject( m_hVM, hFunction );
|
||
sq_pushstring( m_hVM, name.c_str(), name.length() );
|
||
sq_pushstring( m_hVM, signature.c_str(), signature.length() );
|
||
sq_pushstring( m_hVM, pScriptFunction->m_desc.m_pszDescription, -1 );
|
||
sq_call( m_hVM, 5, false, /*false*/ true );
|
||
sq_pop( m_hVM, 1 );
|
||
}
|
||
}
|
||
#endif
|
||
}
|
||
|
||
virtual void RegisterFunction( ScriptFunctionBinding_t *pScriptFunction )
|
||
{
|
||
RegisterFunctionGuts( pScriptFunction );
|
||
}
|
||
|
||
static int custom_index( lua_State *pState )
|
||
{
|
||
InstanceContext_t *pInstanceContext = ( ( InstanceContext_t * )lua_touserdata( pState, 1 ) );
|
||
ScriptClassDesc_t *pVMScriptFunction = pInstanceContext->pClassDesc;
|
||
const char *pszKey = luaL_checkstring( pState, 2 );
|
||
|
||
while( pVMScriptFunction )
|
||
{
|
||
lua_getfield( pState, LUA_REGISTRYINDEX, pVMScriptFunction->m_pszClassname );
|
||
if ( lua_isnil( pState, -1 ) )
|
||
{
|
||
break;
|
||
}
|
||
lua_pushstring( pState, pszKey );
|
||
lua_rawget( pState, -2 );
|
||
|
||
if ( lua_isnil( pState, -1 ) )
|
||
{
|
||
lua_pop( pState, 2 );
|
||
pVMScriptFunction = pVMScriptFunction->m_pBaseDesc;
|
||
}
|
||
else
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
|
||
return 1;
|
||
}
|
||
|
||
/*
|
||
static int custom_gc( lua_State *pState )
|
||
{
|
||
InstanceContext_t *pInstanceContext = ( ( InstanceContext_t * )lua_touserdata( pState, 1 ) );
|
||
|
||
return 0;
|
||
}
|
||
*/
|
||
|
||
// stack good
|
||
virtual bool RegisterClass( ScriptClassDesc_t *pClassDesc )
|
||
{
|
||
if ( luaL_newmetatable( m_LuaState, pClassDesc->m_pszScriptName ) == 0 )
|
||
{
|
||
lua_pop( m_LuaState, 1 );
|
||
return true;
|
||
}
|
||
|
||
// lua_pushcclosure( m_LuaState, custom_gc, 0 );
|
||
// lua_setfield( m_LuaState, -2, "__gc" );
|
||
lua_pushcclosure( m_LuaState, custom_index, 0 );
|
||
lua_setfield( m_LuaState, -2, "__index" );
|
||
|
||
HSCRIPT ClassReference = ( HSCRIPT )( intp )luaL_ref( m_LuaState, LUA_REGISTRYINDEX );
|
||
|
||
for ( int i = 0; i < pClassDesc->m_FunctionBindings.Count(); i++ )
|
||
{
|
||
RegisterFunctionGuts( &pClassDesc->m_FunctionBindings[i], ClassReference );
|
||
}
|
||
|
||
if ( pClassDesc->m_pBaseDesc )
|
||
{
|
||
RegisterClass( pClassDesc->m_pBaseDesc );
|
||
}
|
||
|
||
luaL_unref( m_LuaState, LUA_REGISTRYINDEX, size_cast< int >( ( intp )ClassReference ) );
|
||
|
||
return true;
|
||
}
|
||
|
||
|
||
// stack good
|
||
virtual HSCRIPT RegisterInstance( ScriptClassDesc_t *pClassDesc, void *pInstance )
|
||
{
|
||
HSCRIPT Instance = NULL;
|
||
|
||
if ( !RegisterClass( pClassDesc ) )
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
InstanceContext_t *pInstanceContext = ( InstanceContext_t * )lua_newuserdata( m_LuaState, sizeof( InstanceContext_t ) );
|
||
pInstanceContext->pInstance = pInstance;
|
||
pInstanceContext->pClassDesc = pClassDesc;
|
||
luaL_getmetatable( m_LuaState, pClassDesc->m_pszScriptName );
|
||
lua_setmetatable( m_LuaState, -2 );
|
||
|
||
Instance = ( HSCRIPT )( intp )luaL_ref( m_LuaState, LUA_REGISTRYINDEX );
|
||
|
||
return Instance;
|
||
}
|
||
|
||
// stack good
|
||
virtual void SetInstanceUniqeId( HSCRIPT hInstance, const char *pszId )
|
||
{
|
||
#if 0
|
||
TValue *pValue = ( TValue * )hInstance;
|
||
if ( !hInstance )
|
||
{
|
||
Assert( 0 );
|
||
return;
|
||
}
|
||
|
||
Assert( ttislightuserdata( pValue ) );
|
||
InstanceContext_t *pInstanceContext = ( InstanceContext_t * )( pValue->value.p );
|
||
if ( pInstanceContext == NULL )
|
||
{
|
||
Assert( 0 );
|
||
return;
|
||
}
|
||
|
||
lua_getfield( m_LuaState, LUA_REGISTRYINDEX, pInstanceContext->szName ); //--
|
||
strcpy( pInstanceContext->szName, pszId );
|
||
lua_setfield( m_LuaState, LUA_REGISTRYINDEX, pInstanceContext->szName ); //--
|
||
#endif
|
||
Assert( 0 );
|
||
}
|
||
|
||
// stack good
|
||
virtual void RemoveInstance( HSCRIPT hInstance )
|
||
{
|
||
#if 0
|
||
TValue *pValue = ( TValue * )hInstance;
|
||
if ( !pValue )
|
||
{
|
||
Assert( 0 );
|
||
return;
|
||
}
|
||
|
||
Assert( ttislightuserdata( pValue ) );
|
||
InstanceContext_t *pInstanceContext = ( InstanceContext_t * )( pValue->value.p );
|
||
|
||
lua_pushnil( m_LuaState );
|
||
lua_setfield( m_LuaState, LUA_REGISTRYINDEX, pInstanceContext->szName );
|
||
// lua_pushnil( m_LuaState ); //--
|
||
// lua_setfield( m_LuaState, LUA_GLOBALSINDEX, pInstanceContext->szName ); //--
|
||
|
||
delete pInstanceContext;
|
||
delete pValue;
|
||
#endif
|
||
Assert( 0 );
|
||
}
|
||
|
||
virtual void *GetInstanceValue( HSCRIPT hInstance, ScriptClassDesc_t *pExpectedType = NULL )
|
||
{
|
||
Assert( 0 );
|
||
return NULL;
|
||
}
|
||
|
||
virtual bool GenerateUniqueKey( const char *pszRoot, char *pBuf, int nBufSize )
|
||
{
|
||
Assert( V_strlen(pszRoot) + 32 <= nBufSize );
|
||
Q_snprintf( pBuf, nBufSize, "_%x%I64x_%s", RandomInt(0, 0xfff), m_iUniqueIdSerialNumber++, pszRoot ); // random to limit key compare when serial number gets large
|
||
return true;
|
||
}
|
||
|
||
// stack good
|
||
virtual bool ValueExists( HSCRIPT hScope, const char *pszKey )
|
||
{
|
||
Assert( hScope == NULL );
|
||
|
||
lua_getfield( m_LuaState, LUA_GLOBALSINDEX, pszKey );
|
||
bool bResult = ( lua_isnil( m_LuaState, -1 ) == false );
|
||
|
||
lua_pop( m_LuaState, 1 );
|
||
|
||
return bResult;
|
||
}
|
||
|
||
virtual bool SetValue( HSCRIPT hScope, const char *pszKey, const char *pszValue )
|
||
{
|
||
// Not supported yet.
|
||
Assert(0);
|
||
return false;
|
||
}
|
||
|
||
// stack good
|
||
virtual bool SetValue( HSCRIPT hScope, const char *pszKey, const ScriptVariant_t &value )
|
||
{
|
||
if ( hScope )
|
||
{
|
||
// Msg( "SetValue: SCOPE %s\n", pszKey );
|
||
lua_rawgeti( m_LuaState, LUA_REGISTRYINDEX, size_cast< int >( ( intp )hScope ) );
|
||
lua_pushstring( m_LuaState, pszKey );
|
||
PushVariant( m_LuaState, value );
|
||
lua_settable( m_LuaState, -3 );
|
||
|
||
lua_pop( m_LuaState, 1 );
|
||
}
|
||
else
|
||
{
|
||
// Msg( "SetValue: NORMAL %s\n", pszKey );
|
||
lua_pushstring( m_LuaState, pszKey );
|
||
PushVariant( m_LuaState, value );
|
||
lua_settable( m_LuaState, LUA_GLOBALSINDEX );
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
virtual bool SetValue( HSCRIPT hScope, int nIndex, const ScriptVariant_t &value )
|
||
{
|
||
Assert( hScope );
|
||
|
||
lua_rawgeti( m_LuaState, LUA_REGISTRYINDEX, size_cast< int >( ( intp )hScope ) );
|
||
lua_pushinteger( m_LuaState, nIndex );
|
||
PushVariant( m_LuaState, value );
|
||
lua_settable( m_LuaState, -3 );
|
||
|
||
return true;
|
||
}
|
||
|
||
virtual void CreateTable( ScriptVariant_t &Result )
|
||
{
|
||
lua_newtable( m_LuaState );
|
||
ConvertToVariant( -1, m_LuaState, &Result );
|
||
}
|
||
|
||
// stack good
|
||
virtual int GetNumTableEntries( HSCRIPT hScope )
|
||
{
|
||
// Should this also check for 0?
|
||
if ( hScope == INVALID_HSCRIPT )
|
||
return 0;
|
||
|
||
int nCount = 0;
|
||
|
||
lua_rawgeti( m_LuaState, LUA_REGISTRYINDEX, size_cast< int >( ( intp )hScope ) );
|
||
// int count = lua_objlen( m_LuaState, -1 );
|
||
|
||
lua_pushnil( m_LuaState ); /* first key */
|
||
while ( lua_next( m_LuaState, -2 ) != 0 )
|
||
{
|
||
/* key is at index -2 and value at index -1 */
|
||
// Msg ("%s - %s\n", lua_typename(m_LuaState, lua_type(m_LuaState, -2)), lua_typename(m_LuaState, lua_type(m_LuaState, -1)));
|
||
nCount++;
|
||
lua_pop( m_LuaState, 1 ); /* removes value; keeps key for next iteration */
|
||
}
|
||
|
||
lua_pop( m_LuaState, 1 ); /* removes value; keeps key for next iteration */
|
||
|
||
return nCount;
|
||
}
|
||
|
||
// stack good
|
||
virtual int GetKeyValue( HSCRIPT hScope, int nIterator, ScriptVariant_t *pKey, ScriptVariant_t *pValue )
|
||
{
|
||
int nCount = 0;
|
||
int nStackSize = GetStackSize();
|
||
|
||
lua_rawgeti( m_LuaState, LUA_REGISTRYINDEX, size_cast< int >( ( intp )hScope ) );
|
||
// int count = lua_objlen( m_LuaState, -1 );
|
||
|
||
lua_pushnil( m_LuaState ); /* first key */
|
||
while ( lua_next( m_LuaState, -2 ) != 0 && nCount < nIterator )
|
||
{
|
||
nCount++;
|
||
lua_pop( m_LuaState, 1 ); /* removes value; keeps key for next iteration */
|
||
}
|
||
|
||
// Msg ("%s - %s\n", lua_typename(m_LuaState, lua_type(m_LuaState, -2)), lua_typename(m_LuaState, lua_type(m_LuaState, -1)));
|
||
|
||
ConvertToVariant( -2, m_LuaState, pKey );
|
||
ConvertToVariant( -1, m_LuaState, pValue );
|
||
|
||
lua_pop( m_LuaState, 3 ); /* removes value; keeps key for next iteration */
|
||
|
||
lua_pop( m_LuaState, nStackSize - GetStackSize() );
|
||
|
||
return nCount + 1;
|
||
}
|
||
|
||
virtual bool GetValue( HSCRIPT hScope, const char *pszKey, ScriptVariant_t *pValue )
|
||
{
|
||
int nStackSize = GetStackSize();
|
||
|
||
if ( hScope )
|
||
{
|
||
lua_rawgeti( m_LuaState, LUA_REGISTRYINDEX, size_cast< int >( ( intp )hScope ) );
|
||
lua_getfield( m_LuaState, -1, pszKey );
|
||
if ( lua_isnil( m_LuaState, -1 ) )
|
||
{
|
||
lua_pop( m_LuaState, nStackSize - GetStackSize() );
|
||
return false;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
lua_getfield( m_LuaState, LUA_GLOBALSINDEX, pszKey );
|
||
if ( lua_isnil( m_LuaState, -1 ) )
|
||
{
|
||
lua_pop( m_LuaState, nStackSize - GetStackSize() );
|
||
return false;
|
||
}
|
||
}
|
||
|
||
ConvertToVariant( -1, m_LuaState, pValue );
|
||
lua_pop( m_LuaState, nStackSize - GetStackSize() );
|
||
|
||
return true;
|
||
}
|
||
|
||
virtual bool GetValue( HSCRIPT hScope, int nIndex, ScriptVariant_t *pValue )
|
||
{
|
||
if ( hScope )
|
||
{
|
||
int nStackSize = GetStackSize();
|
||
|
||
lua_rawgeti( m_LuaState, LUA_REGISTRYINDEX, size_cast< int >( ( intp )hScope ) );
|
||
lua_rawgeti( m_LuaState, -1, nIndex );
|
||
if ( lua_isnil( m_LuaState, -1 ) )
|
||
{
|
||
lua_pop( m_LuaState, nStackSize - GetStackSize() );
|
||
return false;
|
||
}
|
||
|
||
ConvertToVariant( -1, m_LuaState, pValue );
|
||
lua_pop( m_LuaState, nStackSize - GetStackSize() );
|
||
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
virtual void ReleaseValue( ScriptVariant_t &value )
|
||
{
|
||
ReleaseVariant( m_LuaState, value );
|
||
}
|
||
|
||
virtual bool ClearValue( HSCRIPT hScope, const char *pszKey )
|
||
{
|
||
Assert( 0 );
|
||
return false;
|
||
}
|
||
|
||
virtual void WriteState( CUtlBuffer *pBuffer )
|
||
{
|
||
Assert( 0 );
|
||
}
|
||
|
||
virtual void ReadState( CUtlBuffer *pBuffer )
|
||
{
|
||
Assert( 0 );
|
||
}
|
||
|
||
virtual void RemoveOrphanInstances()
|
||
{
|
||
Assert( 0 );
|
||
}
|
||
|
||
virtual void DumpState()
|
||
{
|
||
Assert( 0 );
|
||
}
|
||
|
||
//-------------------------------------------------------------
|
||
//
|
||
//-------------------------------------------------------------
|
||
virtual bool RaiseException( const char *pszExceptionText )
|
||
{
|
||
return true;
|
||
}
|
||
|
||
virtual void SetOutputCallback( ScriptOutputFunc_t pFunc )
|
||
{
|
||
m_OutputFunc = pFunc;
|
||
|
||
lua_pushstring( m_LuaState, "print" );
|
||
ScriptOutputFunc_t *pOutputCallback = ( ScriptOutputFunc_t * )lua_newuserdata( m_LuaState, sizeof( ScriptOutputFunc_t ) );
|
||
*pOutputCallback = m_OutputFunc;
|
||
lua_pushcclosure( m_LuaState, PrintFunc, 1 );
|
||
lua_settable( m_LuaState, LUA_GLOBALSINDEX );
|
||
}
|
||
|
||
virtual void SetErrorCallback( ScriptErrorFunc_t pFunc )
|
||
{
|
||
m_ErrorFunc = pFunc;
|
||
}
|
||
};
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
IScriptVM *ScriptCreateLuaVM()
|
||
{
|
||
return new CLuaVM;
|
||
}
|
||
|
||
void ScriptDestroyLuaVM( IScriptVM *pVM )
|
||
{
|
||
CLuaVM *pLuaVM = assert_cast< CLuaVM * >( pVM );
|
||
delete pLuaVM;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
//-----------------------------------------------------------------------------
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
//-----------------------------------------------------------------------------
|
||
|
||
#ifdef VLUA_TEST
|
||
CLuaVM g_LuaVM;
|
||
IScriptVM *g_pScriptVM = &g_LuaVM;
|
||
|
||
//-----------------------------------------------------------------------------
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
#include <time.h>
|
||
#include "fasttimer.h"
|
||
|
||
static void FromScript_AddBehavior( const char *pBehaviorName, HSCRIPT hTable )
|
||
{
|
||
ScriptVariant_t KeyVariant, ValueVariant;
|
||
|
||
Msg( "Behavior: %s\n", pBehaviorName );
|
||
|
||
int nInterator = 0;
|
||
int index = g_pScriptVM->GetNumTableEntries( hTable );
|
||
for( int i = 0; i < index; i++ )
|
||
{
|
||
nInterator = g_pScriptVM->GetKeyValue( hTable, nInterator, &KeyVariant, &ValueVariant );
|
||
|
||
Msg( " %d: %s / %s\n", i, KeyVariant.m_pszString, ValueVariant.m_pszString );
|
||
|
||
g_pScriptVM->ReleaseValue( KeyVariant );
|
||
g_pScriptVM->ReleaseValue( ValueVariant );
|
||
}
|
||
}
|
||
|
||
static Vector MyVectorAdd( Vector A, Vector B )
|
||
{
|
||
return A + B;
|
||
}
|
||
|
||
void TestOutput( const char *pszText )
|
||
{
|
||
Msg( "%s\n", pszText );
|
||
}
|
||
|
||
bool TestError( const char *pszText )
|
||
{
|
||
Msg( "%s\n", pszText );
|
||
|
||
return true;
|
||
}
|
||
|
||
|
||
class CMyClass
|
||
{
|
||
public:
|
||
bool Foo( int );
|
||
void Bar( HSCRIPT TableA, HSCRIPT TableB );
|
||
float FooBar( int, const char * );
|
||
float OverlyTechnicalName( bool );
|
||
};
|
||
|
||
bool CMyClass::Foo( int test )
|
||
{
|
||
return true;
|
||
}
|
||
|
||
void CMyClass::Bar( HSCRIPT TableA, HSCRIPT TableB )
|
||
{
|
||
ScriptVariant_t MyValue;
|
||
|
||
// g_pScriptVM->CreateTable( MyTable );
|
||
|
||
MyValue = 10;
|
||
g_pScriptVM->SetValue( TableA, 1, MyValue );
|
||
MyValue = 20;
|
||
g_pScriptVM->SetValue( TableA, 2, MyValue );
|
||
MyValue = 30;
|
||
g_pScriptVM->SetValue( TableA, 3, MyValue );
|
||
|
||
MyValue = 100;
|
||
g_pScriptVM->SetValue( TableB, 1, MyValue );
|
||
MyValue = 200;
|
||
g_pScriptVM->SetValue( TableB, 2, MyValue );
|
||
MyValue = 300;
|
||
g_pScriptVM->SetValue( TableB, 3, MyValue );
|
||
|
||
// return MyTable;
|
||
}
|
||
|
||
float CMyClass::FooBar( int test1, const char *test2 )
|
||
{
|
||
return 2.34f;
|
||
}
|
||
|
||
float CMyClass::OverlyTechnicalName( bool test )
|
||
{
|
||
return 4.56f;
|
||
}
|
||
|
||
BEGIN_SCRIPTDESC_ROOT_NAMED( CMyClass , "CMyClass", SCRIPT_SINGLETON "" )
|
||
DEFINE_SCRIPTFUNC( Foo, "" )
|
||
DEFINE_SCRIPTFUNC( Bar, "" )
|
||
DEFINE_SCRIPTFUNC( FooBar, "" )
|
||
DEFINE_SCRIPTFUNC_NAMED( OverlyTechnicalName, "SimpleMemberName", "" )
|
||
END_SCRIPTDESC();
|
||
|
||
class CMyDerivedClass : public CMyClass
|
||
{
|
||
public:
|
||
float DerivedFunc() const;
|
||
};
|
||
|
||
BEGIN_SCRIPTDESC( CMyDerivedClass, CMyClass, SCRIPT_SINGLETON "" )
|
||
DEFINE_SCRIPTFUNC( DerivedFunc, "" )
|
||
END_SCRIPTDESC();
|
||
|
||
float CMyDerivedClass::DerivedFunc() const
|
||
{
|
||
return 8.91f;
|
||
}
|
||
|
||
CMyDerivedClass derivedInstance;
|
||
|
||
void AnotherFunction()
|
||
{
|
||
// Manual class exposure
|
||
g_pScriptVM->RegisterClass( GetScriptDescForClass( CMyClass ) );
|
||
|
||
// Auto registration by instance
|
||
g_pScriptVM->RegisterInstance( &derivedInstance, "theInstance" );
|
||
}
|
||
|
||
int main( int argc, const char **argv)
|
||
{
|
||
if ( argc < 2 )
|
||
{
|
||
printf( "No script specified" );
|
||
return 1;
|
||
}
|
||
g_pScriptVM->Init();
|
||
|
||
g_pScriptVM->SetOutputCallback( TestOutput );
|
||
g_pScriptVM->SetErrorCallback( TestError );
|
||
|
||
AnotherFunction();
|
||
|
||
CCycleCount count;
|
||
count.Sample();
|
||
RandomSeed( time( NULL ) ^ count.GetMicroseconds() );
|
||
ScriptRegisterFunction( g_pScriptVM, RandomFloat, "" );
|
||
ScriptRegisterFunction( g_pScriptVM, RandomInt, "" );
|
||
|
||
ScriptRegisterFunction( g_pScriptVM, FromScript_AddBehavior, "" );
|
||
ScriptRegisterFunction( g_pScriptVM, MyVectorAdd, "" );
|
||
|
||
if ( argc == 3 && *argv[2] == 'd' )
|
||
{
|
||
g_pScriptVM->ConnectDebugger();
|
||
}
|
||
|
||
int key;
|
||
CScriptScope scope;
|
||
scope.Init( "TestScope" );
|
||
do
|
||
{
|
||
const char *pszScript = argv[1];
|
||
FILE *hFile = fopen( pszScript, "rb" );
|
||
if ( !hFile )
|
||
{
|
||
printf( "\"%s\" not found.\n", pszScript );
|
||
return 1;
|
||
}
|
||
|
||
int nFileLen = _filelength( _fileno( hFile ) );
|
||
char *pBuf = new char[nFileLen + 1];
|
||
fread( pBuf, 1, nFileLen, hFile );
|
||
pBuf[nFileLen] = 0;
|
||
fclose( hFile );
|
||
|
||
if (1)
|
||
{
|
||
printf( "Executing script \"%s\"\n----------------------------------------\n", pszScript );
|
||
HSCRIPT hScript = g_pScriptVM->CompileScript( pBuf, ( strrchr( pszScript, '\\' ) ? strrchr( pszScript, '\\' ) + 1 : pszScript ) );
|
||
if ( hScript )
|
||
{
|
||
if ( scope.Run( hScript ) != SCRIPT_ERROR )
|
||
{
|
||
printf( "----------------------------------------\n" );
|
||
printf("Script complete. Press q to exit, m to dump memory usage, enter to run again.\n");
|
||
}
|
||
else
|
||
{
|
||
printf( "----------------------------------------\n" );
|
||
printf("Script execution error. Press q to exit, m to dump memory usage, enter to run again.\n");
|
||
}
|
||
g_pScriptVM->ReleaseScript( hScript );
|
||
}
|
||
else
|
||
{
|
||
printf( "----------------------------------------\n" );
|
||
printf("Script failed to compile. Press q to exit, m to dump memory usage, enter to run again.\n");
|
||
}
|
||
}
|
||
key = _getch(); // Keypress before exit
|
||
if ( key == 'm' )
|
||
{
|
||
Msg( "%d\n", g_pMemAlloc->GetSize( NULL ) );
|
||
}
|
||
delete pBuf;
|
||
} while ( key != 'q' );
|
||
|
||
scope.Term();
|
||
// g_pScriptVM->DisconnectDebugger();
|
||
|
||
g_pScriptVM->Shutdown();
|
||
return 0;
|
||
}
|
||
|
||
#endif
|
||
|
||
|
||
// add a check stack auto class to each function
|
||
|