Files
source-sdk-2013/sp/src/utils/vbsp/vscript_vbsp.cpp
samisalreadytaken bf182e1c5d vscript additions and fixes:
baseentity_shared.cpp
baseentity.cpp
c_baseentity.h
c_baseentity.cpp
c_world.h
   - Fixed critical ScriptSetContextThink bugs
   - Added C_BaseEntity::SetContextThink (ScriptSetContextThink)
   - Added C_BaseEntity::SetSize
   - Added C_BaseEntity::SetModel
   - Added C_BaseEntity::Destroy

baseentity.h
baseentity.cpp
   - Removed duplicate functions ScriptSetSize and ScriptUtilRemove

player.cpp
   - Moved player script instance registration before player_spawn event

vscript_server.cpp
   - Added CEntities::FindByClassNearestFacing

vscript_funcs_shared.cpp
   - Added GetFrameCount
   - Added IntervalPerTick

vscript_singletons.cpp
   - Better game event descriptors for CScriptGameEventListener
   - Added ::effects (CEffectsScriptHelper)
   - Added ::Convars (CScriptConvarAccessor)

vscript_shared.cpp
   - Fixed clientside entity printing in script VM

mapbase_con_groups.h
mapbase_con_groups.cpp
   - Improved performance by changing string comparisons to direct array access

vscript_bindings_base.h
vscript_bindings_base.cpp
   - Added CScriptKeyValues::SubKeysToTable

vscript_bindings_math.cpp
   - Added ::SimpleSplineRemapVal
   - Added ::SimpleSplineRemapValClamped
   - Added ::Bias
   - Added ::Gain
   - Added ::SmoothCurve
   - Added ::SmoothCurve_Tweak
   - Added ::ExponentialDecay

vscript_squirrel.nut
   - Added ::Lerp
   - Added ::FLerp
   - Added ::SimpleSpline

vscript_squirrel.cpp
   - Added Vector::_unm
   - Added Vector::Set
   - Added Vector::Add
   - Added Vector::Subtract
   - Added Vector::Multiply
   - Added Vector::Divide
   - Added Vector::DistTo
   - Added Vector::DistToSqr
   - Added Vector::IsEqualTo
   - Added Vector::WithinAABox
   - Added Vector::FromKVString
   - Changed vector print syntax
2021-03-06 02:04:55 +02:00

360 lines
10 KiB
C++

//========= Mapbase - https://github.com/mapbase-source/source-sdk-2013 ============//
//
// Purpose: Mapbase's implementation of VScript in VBSP, allowing users to modify map compilation behavior with scripts.
//
// $NoKeywords: $
//=============================================================================//
#include "tier1/KeyValues.h"
#include "tier1/fmtstr.h"
#include "vbsp.h"
#include "map.h"
#include "fgdlib/fgdlib.h"
#include "convar.h"
#include "vscript_vbsp.h"
#include "vscript_vbsp.nut"
#include "vscript_funcs_vmfs.h"
#include "vscript_funcs_vis.h"
IScriptVM *g_pScriptVM;
IScriptManager *scriptmanager = NULL;
extern ScriptLanguage_t g_iScripting;
extern ScriptClassDesc_t * GetScriptDesc( CBaseEntity * );
// #define VMPROFILE 1
#ifdef VMPROFILE
#define VMPROF_START float debugStartTime = Plat_FloatTime();
#define VMPROF_SHOW( funcname, funcdesc ) DevMsg("***VSCRIPT PROFILE***: %s %s: %6.4f milliseconds\n", (##funcname), (##funcdesc), (Plat_FloatTime() - debugStartTime)*1000.0 );
#else // !VMPROFILE
#define VMPROF_START
#define VMPROF_SHOW
#endif // VMPROFILE
// This is to ensure a dependency exists between the vscript library and the game DLLs
extern int vscript_token;
int vscript_token_hack = vscript_token;
HSCRIPT VScriptCompileScript( const char *pszScriptName, bool bWarnMissing )
{
if ( !g_pScriptVM )
{
return NULL;
}
static const char *pszExtensions[] =
{
"", // SL_NONE
".gm", // SL_GAMEMONKEY
".nut", // SL_SQUIRREL
".lua", // SL_LUA
".py", // SL_PYTHON
};
const char *pszVMExtension = pszExtensions[g_pScriptVM->GetLanguage()];
const char *pszIncomingExtension = V_strrchr( pszScriptName , '.' );
if ( pszIncomingExtension && V_strcmp( pszIncomingExtension, pszVMExtension ) != 0 )
{
Warning( "Script file type does not match VM type\n" );
return NULL;
}
CFmtStr scriptPath;
if ( pszIncomingExtension )
{
scriptPath = pszScriptName;
}
else
{
scriptPath.sprintf( "%s%s", pszScriptName, pszVMExtension );
}
const char *pBase;
CUtlBuffer bufferScript;
if ( g_pScriptVM->GetLanguage() == SL_PYTHON )
{
// python auto-loads raw or precompiled modules - don't load data here
pBase = NULL;
}
else
{
/*
FileFindHandle_t handle = NULL;
const char *file = g_pFullFileSystem->FindFirst( "*", &handle );
while (file)
{
Msg( "File in this directory: %s\n", file );
file = g_pFullFileSystem->FindNext(handle);
}
Msg( "File exists: %d\n", g_pFullFileSystem->FileExists( scriptPath ) );
*/
bool bResult = g_pFullFileSystem->ReadFile( scriptPath, NULL, bufferScript );
if ( !bResult && bWarnMissing )
{
Warning( "Script not found (%s) \n", scriptPath.operator const char *() );
Assert( "Error running script" );
}
pBase = (const char *) bufferScript.Base();
if ( !pBase || !*pBase )
{
return NULL;
}
}
const char *pszFilename = V_strrchr( scriptPath, '\\' );
pszFilename++;
HSCRIPT hScript = g_pScriptVM->CompileScript( pBase, pszFilename );
if ( !hScript )
{
Warning( "FAILED to compile and execute script file named %s\n", scriptPath.operator const char *() );
Assert( "Error running script" );
}
return hScript;
}
static int g_ScriptVBSPRunScriptDepth;
bool VScriptRunScript( const char *pszScriptName, HSCRIPT hScope, bool bWarnMissing )
{
if ( !g_pScriptVM )
{
return false;
}
if ( !pszScriptName || !*pszScriptName )
{
Warning( "Cannot run script: NULL script name\n" );
return false;
}
// Prevent infinite recursion in VM
if ( g_ScriptVBSPRunScriptDepth > 16 )
{
Warning( "IncludeScript stack overflow\n" );
return false;
}
g_ScriptVBSPRunScriptDepth++;
HSCRIPT hScript = VScriptCompileScript( pszScriptName, bWarnMissing );
bool bSuccess = false;
if ( hScript )
{
bSuccess = ( g_pScriptVM->Run( hScript, hScope ) != SCRIPT_ERROR );
if ( !bSuccess )
{
Warning( "Error running script named %s\n", pszScriptName );
Assert( "Error running script" );
}
}
g_ScriptVBSPRunScriptDepth--;
return bSuccess;
}
BEGIN_SCRIPTDESC_ROOT( CMapFile, "Map file" )
DEFINE_SCRIPTFUNC( GetMins, "Get the map's mins." )
DEFINE_SCRIPTFUNC( GetMaxs, "Get the map's maxs." )
DEFINE_SCRIPTFUNC( GetEntityOrigin, "Get the origin of the entity with the specified index." )
DEFINE_SCRIPTFUNC( GetEntityFirstBrush, "Get the first brush ID of the entity with the specified index." )
DEFINE_SCRIPTFUNC( GetEntityNumBrushes, "Get the number of brushes in the entity with the specified index." )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetEntityKeyValues, "GetEntityKeyValues", "Export an entity's keyvalues to two arrays." )
DEFINE_SCRIPTFUNC_NAMED( ScriptAddSimpleEntityKV, "AddSimpleEntityKV", "Add a simple entity from a keyvalue table." )
DEFINE_SCRIPTFUNC_NAMED( ScriptAddInstance, "AddInstance", "Add an instance to the map." )
DEFINE_SCRIPTFUNC( GetNumEntities, "Get the number of entities in the map." )
END_SCRIPTDESC();
static float cvar_getf( const char* sz )
{
ConVarRef cvar(sz);
if ( cvar.IsFlagSet( FCVAR_SERVER_CANNOT_QUERY ) )
return NULL;
return cvar.GetFloat();
}
static bool cvar_setf( const char* sz, float val )
{
ConVarRef cvar(sz);
if ( !cvar.IsValid() )
return false;
if ( cvar.IsFlagSet( FCVAR_SERVER_CANNOT_QUERY ) )
return false;
cvar.SetValue(val);
return true;
}
static const char *GetSource()
{
return source;
}
static const char *GetMapBase()
{
return mapbase;
}
static HSCRIPT GetMainMap()
{
return g_MainMap ? g_MainMap->GetScriptInstance() : NULL;
}
static HSCRIPT GetLoadingMap()
{
return g_LoadingMap ? g_LoadingMap->GetScriptInstance() : NULL;
}
static const char *DoUniqueString( const char *pszBase )
{
static char szBuf[512];
g_pScriptVM->GenerateUniqueKey( pszBase, szBuf, ARRAYSIZE(szBuf) );
return szBuf;
}
bool DoIncludeScript( const char *pszScript, HSCRIPT hScope )
{
if ( !VScriptRunScript( pszScript, hScope, true ) )
{
g_pScriptVM->RaiseException( CFmtStr( "Failed to include script \"%s\"", ( pszScript ) ? pszScript : "unknown" ) );
return false;
}
return true;
}
extern qboolean glview;
extern qboolean onlyents;
extern bool onlyprops;
extern qboolean noleaktest;
extern qboolean verboseentities;
extern qboolean g_bLowPriority;
extern bool g_bKeepStaleZip;
extern bool g_bNoDefaultCubemaps;
extern bool g_bSkyboxCubemaps;
extern int g_iDefaultCubemapSize;
bool VScriptVBSPInit()
{
VMPROF_START
if( g_iScripting != SL_NONE && scriptmanager != NULL )
{
if ( g_pScriptVM == NULL )
g_pScriptVM = scriptmanager->CreateVM( g_iScripting );
if( g_pScriptVM )
{
Log( "VSCRIPT VBSP: Started VScript virtual machine using script language '%s'\n", g_pScriptVM->GetLanguageName() );
ScriptRegisterFunction( g_pScriptVM, cvar_getf, "Gets the value of the given cvar, as a float." );
ScriptRegisterFunction( g_pScriptVM, cvar_setf, "Sets the value of the given cvar, as a float." );
ScriptRegisterFunction( g_pScriptVM, GetSource, "Gets the base directory of the first map loaded." );
ScriptRegisterFunction( g_pScriptVM, GetMapBase, "Gets the base name of the first map loaded." );
ScriptRegisterFunction( g_pScriptVM, GetMainMap, "Gets the first map loaded." );
ScriptRegisterFunction( g_pScriptVM, GetLoadingMap, "Gets the map which is currently loading (e.g. an instance)." );
ScriptRegisterFunction( g_pScriptVM, DoUniqueString, SCRIPT_ALIAS( "UniqueString", "Generate a string guaranteed to be unique across the life of the script VM, with an optional root string. Useful for adding data to tables when not sure what keys are already in use in that table." ) );
ScriptRegisterFunction( g_pScriptVM, DoIncludeScript, "Execute a script (internal)" );
ScriptRegisterConstantNamed( g_pScriptVM, GameData::NAME_FIXUP_PREFIX, "NAME_FIXUP_PREFIX", "Prefix name fixup" );
ScriptRegisterConstantNamed( g_pScriptVM, GameData::NAME_FIXUP_POSTFIX, "NAME_FIXUP_PREFIX", "Postfix name fixup" );
ScriptRegisterConstantNamed( g_pScriptVM, GameData::NAME_FIXUP_NONE, "NAME_FIXUP_NONE", "No name fixup" );
ScriptRegisterConstant( g_pScriptVM, microvolume, "" );
ScriptRegisterConstant( g_pScriptVM, noprune, "" );
ScriptRegisterConstant( g_pScriptVM, glview, "" );
ScriptRegisterConstant( g_pScriptVM, nodetail, "" );
ScriptRegisterConstant( g_pScriptVM, fulldetail, "" );
ScriptRegisterConstant( g_pScriptVM, onlyents, "" );
ScriptRegisterConstant( g_pScriptVM, onlyprops, "" );
ScriptRegisterConstant( g_pScriptVM, nomerge, "" );
ScriptRegisterConstant( g_pScriptVM, nomergewater, "" );
ScriptRegisterConstant( g_pScriptVM, nowater, "" );
ScriptRegisterConstant( g_pScriptVM, nocsg, "" );
ScriptRegisterConstant( g_pScriptVM, noweld, "" );
ScriptRegisterConstant( g_pScriptVM, noshare, "" );
ScriptRegisterConstant( g_pScriptVM, nosubdiv, "" );
ScriptRegisterConstant( g_pScriptVM, notjunc, "" );
ScriptRegisterConstant( g_pScriptVM, noopt, "" );
ScriptRegisterConstant( g_pScriptVM, noleaktest, "" );
ScriptRegisterConstant( g_pScriptVM, verboseentities, "" );
ScriptRegisterConstant( g_pScriptVM, dumpcollide, "" );
ScriptRegisterConstant( g_pScriptVM, g_bLowPriority, "" );
ScriptRegisterConstant( g_pScriptVM, g_DumpStaticProps, "" );
ScriptRegisterConstant( g_pScriptVM, g_bSkyVis, "" );
ScriptRegisterConstant( g_pScriptVM, g_bLightIfMissing, "" );
ScriptRegisterConstant( g_pScriptVM, g_snapAxialPlanes, "" );
ScriptRegisterConstant( g_pScriptVM, g_bKeepStaleZip, "" );
ScriptRegisterConstant( g_pScriptVM, g_NodrawTriggers, "" );
ScriptRegisterConstant( g_pScriptVM, g_DisableWaterLighting, "" );
ScriptRegisterConstant( g_pScriptVM, g_bAllowDetailCracks, "" );
ScriptRegisterConstant( g_pScriptVM, g_bNoVirtualMesh, "" );
ScriptRegisterConstant( g_pScriptVM, g_bNoHiddenManifestMaps, "" );
ScriptRegisterConstant( g_pScriptVM, g_bNoDefaultCubemaps, "" );
ScriptRegisterConstant( g_pScriptVM, g_bSkyboxCubemaps, "" );
ScriptRegisterConstant( g_pScriptVM, g_iDefaultCubemapSize, "" );
if (g_iScripting == SL_SQUIRREL)
{
g_pScriptVM->Run( g_Script_vscript_vbsp );
}
RegisterVMFScriptFunctions();
// Run the map's script
char script[96];
Q_snprintf( script, sizeof(script), "%s_vbsp", source );
//Msg("VBSP script: \"%s\"\n", script);
VScriptRunScript( script, true );
VMPROF_SHOW( g_iScripting, "virtual machine startup" );
return true;
}
else
{
DevWarning("VM Did not start!\n");
}
}
else
{
Log( "\nVSCRIPT: Scripting is disabled.\n" );
}
g_pScriptVM = NULL;
return false;
}
void VScriptVBSPTerm()
{
if( g_pScriptVM != NULL )
{
if( g_pScriptVM )
{
scriptmanager->DestroyVM( g_pScriptVM );
g_pScriptVM = NULL;
}
}
}