2021-12-25 22:36:38 +01:00
//=============================================================================//
//
// Purpose: Squirrel VM
//
//=============================================================================//
# include "core/stdafx.h"
# include "core/logdef.h"
# include "tier0/cvar.h"
# include "tier0/IConVar.h"
2022-01-14 20:45:36 +01:00
# include "tier0/commandline.h"
2021-12-25 22:36:38 +01:00
# include "engine/sys_utils.h"
2022-02-08 16:32:00 +01:00
# ifdef DEDICATED
# include "engine/sv_rcon.h"
# endif // DEDICATED
2022-02-19 02:31:16 +01:00
# include "vgui/vgui_debugpanel.h"
2021-12-25 22:36:38 +01:00
# include "gameui/IConsole.h"
2022-01-14 20:45:36 +01:00
# include "squirrel/sqvm.h"
2022-01-16 00:35:39 +01:00
# include "squirrel/sqinit.h"
2021-12-25 22:36:38 +01:00
//---------------------------------------------------------------------------------
// Purpose: prints the output of each VM to the console
2022-03-04 15:34:09 +01:00
// Input : *sqvm -
// *fmt -
// ... -
2021-12-25 22:36:38 +01:00
//---------------------------------------------------------------------------------
void * HSQVM_PrintFunc ( void * sqvm , char * fmt , . . . )
{
2022-02-17 18:00:29 +01:00
static int vmIdx { } ;
// We use the sqvm pointer as index for SDK usage as the function prototype has to match assembly.
switch ( reinterpret_cast < int > ( sqvm ) )
{
case 0 :
vmIdx = 0 ;
break ;
case 1 :
vmIdx = 1 ;
break ;
case 2 :
vmIdx = 2 ;
break ;
case 3 :
vmIdx = 3 ;
break ;
default :
2021-12-25 22:36:38 +01:00
# ifdef GAMEDLL_S3
2022-02-17 18:00:29 +01:00
vmIdx = * reinterpret_cast < int * > ( reinterpret_cast < std : : uintptr_t > ( sqvm ) + 0x18 ) ;
2022-01-14 20:45:36 +01:00
# else // TODO [ AMOS ]: nothing equal to 'rdx + 18h' exist in the vm structs for anything below S3.
2022-02-17 18:00:29 +01:00
vmIdx = 3 ;
2021-12-25 22:36:38 +01:00
# endif
2022-02-17 18:00:29 +01:00
break ;
}
2022-01-14 20:45:36 +01:00
static char buf [ 1024 ] = { } ;
2022-02-17 18:00:29 +01:00
static std : : regex rxAnsiExp ( " \\ \033 \\ [.*?m " ) ;
2021-12-25 22:36:38 +01:00
2022-01-14 20:45:36 +01:00
static std : : shared_ptr < spdlog : : logger > iconsole = spdlog : : get ( " game_console " ) ;
static std : : shared_ptr < spdlog : : logger > wconsole = spdlog : : get ( " win_console " ) ;
static std : : shared_ptr < spdlog : : logger > sqlogger = spdlog : : get ( " sqvm_print_logger " ) ;
2021-12-25 22:36:38 +01:00
2022-01-14 20:45:36 +01:00
{ /////////////////////////////
va_list args { } ;
va_start ( args , fmt ) ;
2021-12-25 22:36:38 +01:00
2022-01-14 20:45:36 +01:00
vsnprintf ( buf , sizeof ( buf ) , fmt , args ) ;
2021-12-25 22:36:38 +01:00
2022-01-14 20:45:36 +01:00
buf [ sizeof ( buf ) - 1 ] = 0 ;
va_end ( args ) ;
} /////////////////////////////
2021-12-25 22:36:38 +01:00
2022-01-14 20:45:36 +01:00
std : : string vmStr = SQVM_LOG_T [ vmIdx ] . c_str ( ) ;
2021-12-25 22:36:38 +01:00
vmStr . append ( buf ) ;
2022-01-09 17:17:05 +01:00
if ( sq_showvmoutput - > GetInt ( ) > 0 )
2021-12-25 22:36:38 +01:00
{
sqlogger - > debug ( vmStr ) ;
}
2022-01-09 17:17:05 +01:00
if ( sq_showvmoutput - > GetInt ( ) > 1 )
2021-12-25 22:36:38 +01:00
{
2022-01-14 20:45:36 +01:00
if ( ! g_bSpdLog_UseAnsiClr )
{
wconsole - > debug ( vmStr ) ;
2022-02-08 16:32:00 +01:00
# ifdef DEDICATED
g_pRConServer - > Send ( vmStr . c_str ( ) ) ;
# endif // DEDICATED
2022-01-14 20:45:36 +01:00
}
else
{
std : : string vmStrAnsi = SQVM_ANSI_LOG_T [ vmIdx ] . c_str ( ) ;
vmStrAnsi . append ( buf ) ;
wconsole - > debug ( vmStrAnsi ) ;
2022-02-08 16:32:00 +01:00
# ifdef DEDICATED
g_pRConServer - > Send ( vmStrAnsi . c_str ( ) ) ;
# endif // DEDICATED
2022-01-14 20:45:36 +01:00
}
2021-12-25 22:36:38 +01:00
# ifndef DEDICATED
2022-02-17 18:00:29 +01:00
vmStr = std : : regex_replace ( vmStr , rxAnsiExp , " " ) ;
2022-01-14 20:45:36 +01:00
iconsole - > debug ( vmStr ) ;
if ( sq_showvmoutput - > GetInt ( ) > 2 )
{
2022-01-22 15:41:30 +01:00
std : : string s = g_spd_sys_w_oss . str ( ) ;
g_pIConsole - > m_ivConLog . push_back ( Strdup ( s . c_str ( ) ) ) ;
2022-02-17 18:00:29 +01:00
g_pLogSystem . AddLog ( static_cast < LogType_t > ( vmIdx ) , s ) ;
2022-02-08 16:32:00 +01:00
g_spd_sys_w_oss . str ( " " ) ;
g_spd_sys_w_oss . clear ( ) ;
2022-01-14 20:45:36 +01:00
}
2021-12-25 22:36:38 +01:00
# endif // !DEDICATED
}
return NULL ;
}
//---------------------------------------------------------------------------------
// Purpose: prints the warning output of each VM to the console
2022-03-04 15:34:09 +01:00
// Input : *sqvm -
// a2 -
// a3 -
// *nStringSize -
// **ppString -
2021-12-25 22:36:38 +01:00
//---------------------------------------------------------------------------------
void * HSQVM_WarningFunc ( void * sqvm , int a2 , int a3 , int * nStringSize , void * * ppString )
{
2022-01-22 15:41:30 +01:00
static void * retaddr = reinterpret_cast < void * > ( p_SQVM_WarningCmd . Offset ( 0x10 ) . FindPatternSelf ( " 85 ?? ?? 99 " , ADDRESS : : Direction : : DOWN ) . GetPtr ( ) ) ;
2021-12-25 22:36:38 +01:00
void * result = SQVM_WarningFunc ( sqvm , a2 , a3 , nStringSize , ppString ) ;
2022-01-14 20:45:36 +01:00
2022-01-22 15:41:30 +01:00
if ( retaddr ! = _ReturnAddress ( ) ) // Check if its SQVM_Warning calling.
2021-12-25 22:36:38 +01:00
{
return result ; // If not return.
}
# ifdef GAMEDLL_S3
int vmIdx = * ( int * ) ( ( std : : uintptr_t ) sqvm + 0x18 ) ;
2022-01-14 20:45:36 +01:00
# else // TODO [ AMOS ]: nothing equal to 'rdx + 18h' exist in the vm structs for anything below S3.
2021-12-25 22:36:38 +01:00
int vmIdx = 3 ;
# endif
2022-01-14 20:45:36 +01:00
static std : : shared_ptr < spdlog : : logger > iconsole = spdlog : : get ( " game_console " ) ;
static std : : shared_ptr < spdlog : : logger > wconsole = spdlog : : get ( " win_console " ) ;
static std : : shared_ptr < spdlog : : logger > sqlogger = spdlog : : get ( " sqvm_warn_logger " ) ;
2021-12-25 22:36:38 +01:00
2022-01-22 15:41:30 +01:00
std : : string vmStr = SQVM_WARNING_LOG_T [ vmIdx ] . c_str ( ) ;
2022-01-14 20:45:36 +01:00
std : : string svConstructor ( ( char * ) * ppString , * nStringSize ) ; // Get string from memory via std::string constructor.
vmStr . append ( svConstructor ) ;
2021-12-25 22:36:38 +01:00
2022-01-09 17:17:05 +01:00
if ( sq_showvmwarning - > GetInt ( ) > 0 )
2021-12-25 22:36:38 +01:00
{
sqlogger - > debug ( vmStr ) ; // Emit to file.
}
2022-01-09 17:17:05 +01:00
if ( sq_showvmwarning - > GetInt ( ) > 1 )
2021-12-25 22:36:38 +01:00
{
2022-01-14 20:45:36 +01:00
if ( ! g_bSpdLog_UseAnsiClr )
{
wconsole - > debug ( vmStr ) ;
2022-02-08 16:32:00 +01:00
# ifdef DEDICATED
g_pRConServer - > Send ( vmStr . c_str ( ) ) ;
# endif // DEDICATED
2022-01-14 20:45:36 +01:00
}
else
{
2022-01-22 15:41:30 +01:00
std : : string vmStrAnsi = SQVM_WARNING_ANSI_LOG_T [ vmIdx ] . c_str ( ) ;
2022-01-14 20:45:36 +01:00
vmStrAnsi . append ( svConstructor ) ;
wconsole - > debug ( vmStrAnsi ) ;
2022-02-08 16:32:00 +01:00
# ifdef DEDICATED
g_pRConServer - > Send ( vmStrAnsi . c_str ( ) ) ;
# endif // DEDICATED
2022-01-14 20:45:36 +01:00
}
2021-12-25 22:36:38 +01:00
# ifndef DEDICATED
2022-01-14 20:45:36 +01:00
g_spd_sys_w_oss . str ( " " ) ;
g_spd_sys_w_oss . clear ( ) ;
iconsole - > debug ( vmStr ) ; // Emit to in-game console.
std : : string s = g_spd_sys_w_oss . str ( ) ;
g_pIConsole - > m_ivConLog . push_back ( Strdup ( s . c_str ( ) ) ) ;
if ( sq_showvmwarning - > GetInt ( ) > 2 )
{
2022-02-17 18:00:29 +01:00
g_pLogSystem . AddLog ( LogType_t : : WARNING_C , s ) ;
2022-01-14 20:45:36 +01:00
g_pIConsole - > m_ivConLog . push_back ( Strdup ( s . c_str ( ) ) ) ;
}
2021-12-25 22:36:38 +01:00
# endif // !DEDICATED
}
return result ;
}
2022-03-04 15:34:09 +01:00
//---------------------------------------------------------------------------------
// Purpose: prints the compile error and context to the console
// Input : *sqvm -
// *pszError -
// *pszFile -
// nLine -
// nColumn -
//---------------------------------------------------------------------------------
void HSQVM_ErrorFunc ( void * sqvm , const char * pszError , const char * pszFile , unsigned int nLine , int nColumn )
{
static int vmIdx { } ;
static char szContextBuf [ 256 ] { } ;
# ifdef GAMEDLL_S3
vmIdx = * reinterpret_cast < int * > ( reinterpret_cast < std : : uintptr_t > ( sqvm ) + 0x18 ) ;
# else // TODO [ AMOS ]: nothing equal to 'rdx + 18h' exist in the vm structs for anything below S3.
vmIdx = 3 ;
# endif
SQVM_GetErrorLine ( pszFile , nLine , szContextBuf , sizeof ( szContextBuf ) ) ;
Error ( eDLL_T : : SERVER , " %s SCRIPT COMPILE ERROR: %s \n " , SQVM_TYPE_T [ vmIdx ] . c_str ( ) , pszError ) ;
Error ( eDLL_T : : SERVER , " -> %s \n \n " , szContextBuf ) ;
Error ( eDLL_T : : SERVER , " %s line [%d] column [%d] \n " , pszFile , nLine , nColumn ) ;
}
2021-12-25 22:36:38 +01:00
//---------------------------------------------------------------------------------
2022-01-19 19:02:18 +01:00
// Purpose: prints the global include file the compiler loads for loading scripts
2022-03-04 15:34:09 +01:00
// Input : *szRsonName -
2021-12-25 22:36:38 +01:00
//---------------------------------------------------------------------------------
void * HSQVM_LoadRson ( const char * szRsonName )
{
2022-01-19 19:02:18 +01:00
if ( sq_showrsonloading - > GetBool ( ) )
2021-12-25 22:36:38 +01:00
{
2022-01-19 19:02:18 +01:00
DevMsg ( eDLL_T : : ENGINE , " \n " ) ;
DevMsg ( eDLL_T : : ENGINE , " ______________________________________________________________ \n " ) ;
DevMsg ( eDLL_T : : ENGINE , " ] RSON_SQVM -------------------------------------------------- \n " ) ;
DevMsg ( eDLL_T : : ENGINE , " ] PATH: '%s' \n " , szRsonName ) ;
DevMsg ( eDLL_T : : ENGINE , " -------------------------------------------------------------- \n " ) ;
DevMsg ( eDLL_T : : ENGINE , " \n " ) ;
2021-12-25 22:36:38 +01:00
}
return SQVM_LoadRson ( szRsonName ) ;
}
//---------------------------------------------------------------------------------
2022-01-19 19:02:18 +01:00
// Purpose: prints the scripts the compiler loads from global include to be compiled
2022-03-04 15:34:09 +01:00
// Input : *sqvm -
// *szScriptPath -
// nFlag -
2021-12-25 22:36:38 +01:00
//---------------------------------------------------------------------------------
bool HSQVM_LoadScript ( void * sqvm , const char * szScriptPath , const char * szScriptName , int nFlag )
{
2022-01-09 17:17:05 +01:00
if ( sq_showscriptloading - > GetBool ( ) )
2021-12-25 22:36:38 +01:00
{
2022-01-19 19:02:18 +01:00
DevMsg ( eDLL_T : : ENGINE , " Loading SQVM Script '%s' \n " , szScriptName ) ;
2021-12-25 22:36:38 +01:00
}
///////////////////////////////////////////////////////////////////////////////
return SQVM_LoadScript ( sqvm , szScriptPath , szScriptName , nFlag ) ;
}
2022-01-16 00:35:39 +01:00
//---------------------------------------------------------------------------------
2022-02-08 16:32:00 +01:00
// Purpose: registers and exposes code functions to target context
2022-03-04 15:34:09 +01:00
// Input : *sqvm -
// *szName -
// *szHelpString -
// *szRetValType -
// *szArgTypes -
// *pFunction -
2022-01-16 00:35:39 +01:00
//---------------------------------------------------------------------------------
2021-12-25 22:36:38 +01:00
void HSQVM_RegisterFunction ( void * sqvm , const char * szName , const char * szHelpString , const char * szRetValType , const char * szArgTypes , void * pFunction )
{
SQFuncRegistration * sqFunc = new SQFuncRegistration ( ) ;
sqFunc - > m_szScriptName = szName ;
sqFunc - > m_szNativeName = szName ;
sqFunc - > m_szHelpString = szHelpString ;
sqFunc - > m_szRetValType = szRetValType ;
sqFunc - > m_szArgTypes = szArgTypes ;
sqFunc - > m_pFunction = pFunction ;
SQVM_RegisterFunc ( sqvm , sqFunc , 1 ) ;
}
2022-01-16 00:35:39 +01:00
//---------------------------------------------------------------------------------
2022-02-08 16:32:00 +01:00
// Purpose: registers script functions in SERVER context
2022-03-04 15:34:09 +01:00
// Input : *sqvm -
2022-01-16 00:35:39 +01:00
//---------------------------------------------------------------------------------
void RegisterServerScriptFunctions ( void * sqvm )
{
2022-01-19 19:02:18 +01:00
HSQVM_RegisterFunction ( sqvm , " SDKNativeTest " , " Native SERVER test function " , " void " , " " , & VSquirrel : : SHARED : : Script_NativeTest ) ;
2022-01-16 00:35:39 +01:00
}
# ifndef DEDICATED
//---------------------------------------------------------------------------------
2022-02-08 16:32:00 +01:00
// Purpose: registers script functions in CLIENT context
2022-03-04 15:34:09 +01:00
// Input : *sqvm -
2022-01-16 00:35:39 +01:00
//---------------------------------------------------------------------------------
void RegisterClientScriptFunctions ( void * sqvm )
2021-12-25 22:36:38 +01:00
{
2022-01-19 19:02:18 +01:00
HSQVM_RegisterFunction ( sqvm , " SDKNativeTest " , " Native CLIENT test function " , " void " , " " , & VSquirrel : : SHARED : : Script_NativeTest ) ;
2021-12-25 22:36:38 +01:00
}
2022-01-16 00:35:39 +01:00
//---------------------------------------------------------------------------------
2022-02-08 16:32:00 +01:00
// Purpose: registers script functions in UI context
2022-03-04 15:34:09 +01:00
// Input : *sqvm -
2022-01-16 00:35:39 +01:00
//---------------------------------------------------------------------------------
2021-12-25 22:36:38 +01:00
void RegisterUIScriptFunctions ( void * sqvm )
{
2022-01-19 19:02:18 +01:00
HSQVM_RegisterFunction ( sqvm , " SDKNativeTest " , " Native UI test function " , " void " , " " , & VSquirrel : : SHARED : : Script_NativeTest ) ;
2022-01-15 17:57:18 +00:00
// functions for retrieving server browser data
2022-01-16 00:35:39 +01:00
HSQVM_RegisterFunction ( sqvm , " GetServerName " , " Gets the name of the server at the specified index of the server list " , " string " , " int " , & VSquirrel : : UI : : GetServerName ) ;
HSQVM_RegisterFunction ( sqvm , " GetServerPlaylist " , " Gets the playlist of the server at the specified index of the server list " , " string " , " int " , & VSquirrel : : UI : : GetServerPlaylist ) ;
HSQVM_RegisterFunction ( sqvm , " GetServerMap " , " Gets the map of the server at the specified index of the server list " , " string " , " int " , & VSquirrel : : UI : : GetServerMap ) ;
HSQVM_RegisterFunction ( sqvm , " GetServerCount " , " Gets the number of public servers " , " int " , " " , & VSquirrel : : UI : : GetServerCount ) ;
2022-01-15 17:57:18 +00:00
// misc main menu functions
2022-01-16 00:35:39 +01:00
HSQVM_RegisterFunction ( sqvm , " GetSDKVersion " , " Gets the SDK version as a string " , " string " , " " , & VSquirrel : : UI : : GetSDKVersion ) ;
HSQVM_RegisterFunction ( sqvm , " GetPromoData " , " Gets promo data for specified slot type " , " string " , " int " , & VSquirrel : : UI : : GetPromoData ) ;
2022-01-15 17:57:18 +00:00
// functions for connecting to servers
2022-01-16 00:35:39 +01:00
HSQVM_RegisterFunction ( sqvm , " CreateServer " , " Start server with the specified settings " , " void " , " string,string,string,int " , & VSquirrel : : UI : : CreateServerFromMenu ) ;
HSQVM_RegisterFunction ( sqvm , " SetEncKeyAndConnect " , " Set the encryption key to that of the specified server and connects to it " , " void " , " int " , & VSquirrel : : UI : : SetEncKeyAndConnect ) ;
HSQVM_RegisterFunction ( sqvm , " JoinPrivateServerFromMenu " , " Joins private server by token " , " void " , " string " , & VSquirrel : : UI : : JoinPrivateServerFromMenu ) ;
HSQVM_RegisterFunction ( sqvm , " GetPrivateServerMessage " , " Gets private server join status message " , " string " , " string " , & VSquirrel : : UI : : GetPrivateServerMessage ) ;
HSQVM_RegisterFunction ( sqvm , " ConnectToIPFromMenu " , " Joins server by ip and encryption key " , " void " , " string,string " , & VSquirrel : : UI : : ConnectToIPFromMenu ) ;
2022-01-15 17:57:18 +00:00
2022-01-16 00:35:39 +01:00
HSQVM_RegisterFunction ( sqvm , " GetAvailableMaps " , " Gets an array of all the available maps that can be used to host a server " , " array<string> " , " " , & VSquirrel : : UI : : GetAvailableMaps ) ;
2021-12-25 22:36:38 +01:00
}
2022-01-16 00:35:39 +01:00
//---------------------------------------------------------------------------------
2022-02-08 16:32:00 +01:00
// Purpose: Origin functions are the last to be registered in UI context, we register anything ours below
2022-03-04 15:34:09 +01:00
// Input : *sqvm -
2022-02-08 16:32:00 +01:00
// TODO : Hook 'CreateVM' instead
2022-01-16 00:35:39 +01:00
//---------------------------------------------------------------------------------
2022-01-15 15:25:19 +01:00
void HSQVM_RegisterOriginFuncs ( void * sqvm )
{
2022-03-28 12:09:40 +02:00
if ( sqvm = = * g_pUIVM . RCast < void * * > ( ) )
2022-01-15 15:25:19 +01:00
RegisterUIScriptFunctions ( sqvm ) ;
else
RegisterClientScriptFunctions ( sqvm ) ;
return SQVM_RegisterOriginFuncs ( sqvm ) ;
}
2022-01-16 00:35:39 +01:00
# endif // !DEDICATED
2022-01-15 15:25:19 +01:00
2021-12-25 22:36:38 +01:00
void SQVM_Attach ( )
{
DetourAttach ( ( LPVOID * ) & SQVM_PrintFunc , & HSQVM_PrintFunc ) ;
DetourAttach ( ( LPVOID * ) & SQVM_WarningFunc , & HSQVM_WarningFunc ) ;
2022-03-04 15:34:09 +01:00
DetourAttach ( ( LPVOID * ) & SQVM_ErrorFunc , & HSQVM_ErrorFunc ) ;
2021-12-25 22:36:38 +01:00
DetourAttach ( ( LPVOID * ) & SQVM_LoadRson , & HSQVM_LoadRson ) ;
DetourAttach ( ( LPVOID * ) & SQVM_LoadScript , & HSQVM_LoadScript ) ;
2022-01-16 00:35:39 +01:00
# ifndef DEDICATED
2022-01-15 15:25:19 +01:00
DetourAttach ( ( LPVOID * ) & SQVM_RegisterOriginFuncs , & HSQVM_RegisterOriginFuncs ) ;
2022-01-16 00:35:39 +01:00
# endif // !DEDICATED
2021-12-25 22:36:38 +01:00
}
void SQVM_Detach ( )
{
DetourDetach ( ( LPVOID * ) & SQVM_PrintFunc , & HSQVM_PrintFunc ) ;
DetourDetach ( ( LPVOID * ) & SQVM_WarningFunc , & HSQVM_WarningFunc ) ;
2022-03-04 15:34:09 +01:00
DetourDetach ( ( LPVOID * ) & SQVM_ErrorFunc , & HSQVM_ErrorFunc ) ;
2021-12-25 22:36:38 +01:00
DetourDetach ( ( LPVOID * ) & SQVM_LoadRson , & HSQVM_LoadRson ) ;
DetourDetach ( ( LPVOID * ) & SQVM_LoadScript , & HSQVM_LoadScript ) ;
2022-01-16 00:35:39 +01:00
# ifndef DEDICATED
2022-01-15 15:25:19 +01:00
DetourDetach ( ( LPVOID * ) & SQVM_RegisterOriginFuncs , & HSQVM_RegisterOriginFuncs ) ;
2022-01-16 00:35:39 +01:00
# endif // !DEDICATED
2021-12-25 22:36:38 +01:00
}
///////////////////////////////////////////////////////////////////////////////
bool g_bSQVM_WarnFuncCalled = false ;