Integrating vscript interface code (based on Alien Swarm)

This commit is contained in:
James Mitchell 2020-05-04 16:25:15 +10:00
parent af85131deb
commit d840c57b4a
53 changed files with 5128 additions and 134 deletions

View File

@ -281,6 +281,11 @@ BEGIN_DATADESC( C_ClientRagdoll )
END_DATADESC()
BEGIN_ENT_SCRIPTDESC( C_BaseAnimating, C_BaseEntity, "Animating models client-side" )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetPoseParameter, "SetPoseParameter", "Set the specified pose parameter to the specified value" )
DEFINE_SCRIPTFUNC( IsSequenceFinished, "Ask whether the main sequence is done playing" )
END_SCRIPTDESC();
C_ClientRagdoll::C_ClientRagdoll( bool bRestoring )
{
m_iCurrentFriction = 0;
@ -1403,6 +1408,15 @@ float C_BaseAnimating::ClampCycle( float flCycle, bool isLooping )
return flCycle;
}
void C_BaseAnimating::ScriptSetPoseParameter(const char* szName, float fValue)
{
CStudioHdr* pHdr = GetModelPtr();
if (pHdr == NULL)
return;
int iPoseParam = LookupPoseParameter(pHdr, szName);
SetPoseParameter(pHdr, iPoseParam, fValue);
}
void C_BaseAnimating::GetCachedBoneMatrix( int boneIndex, matrix3x4_t &out )
{

View File

@ -95,6 +95,7 @@ public:
DECLARE_CLIENTCLASS();
DECLARE_PREDICTABLE();
DECLARE_INTERPOLATION();
DECLARE_ENT_SCRIPTDESC();
enum
{
@ -445,6 +446,7 @@ public:
virtual bool IsViewModel() const;
void ScriptSetPoseParameter(const char* szName, float fValue);
protected:
// View models scale their attachment positions to account for FOV. To get the unmodified
// attachment position (like if you're rendering something else during the view model's DrawModel call),

View File

@ -44,6 +44,8 @@
#include "viewrender.h"
#endif
#include "gamestringpool.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
@ -423,6 +425,13 @@ BEGIN_RECV_TABLE_NOBASE( C_BaseEntity, DT_AnimTimeMustBeFirst )
RecvPropInt( RECVINFO(m_flAnimTime), 0, RecvProxy_AnimTime ),
END_RECV_TABLE()
BEGIN_ENT_SCRIPTDESC_ROOT( C_BaseEntity, "Root class of all client-side entities" )
DEFINE_SCRIPTFUNC_NAMED( GetAbsOrigin, "GetOrigin", "" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetForward, "GetForwardVector", "Get the forward vector of the entity" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetLeft, "GetLeftVector", "Get the left vector of the entity" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetUp, "GetUpVector", "Get the up vector of the entity" )
DEFINE_SCRIPTFUNC( GetTeamNumber, "Gets this entity's team" )
END_SCRIPTDESC();
#ifndef NO_ENTITY_PREDICTION
BEGIN_RECV_TABLE_NOBASE( C_BaseEntity, DT_PredictableId )
@ -466,6 +475,8 @@ BEGIN_RECV_TABLE_NOBASE(C_BaseEntity, DT_BaseEntity)
RecvPropInt( RECVINFO_NAME(m_hNetworkMoveParent, moveparent), 0, RecvProxy_IntToMoveParent ),
RecvPropInt( RECVINFO( m_iParentAttachment ) ),
RecvPropString(RECVINFO(m_iName)),
RecvPropInt( "movetype", 0, SIZEOF_IGNORE, 0, RecvProxy_MoveType ),
RecvPropInt( "movecollide", 0, SIZEOF_IGNORE, 0, RecvProxy_MoveCollide ),
RecvPropDataTable( RECVINFO_DT( m_Collision ), 0, &REFERENCE_RECV_TABLE(DT_CollisionProperty) ),
@ -1165,6 +1176,7 @@ void C_BaseEntity::Term()
g_Predictables.RemoveFromPredictablesList( GetClientHandle() );
}
// If it's play simulated, remove from simulation list if the player still exists...
if ( IsPlayerSimulated() && C_BasePlayer::GetLocalPlayer() )
{
@ -1201,6 +1213,12 @@ void C_BaseEntity::Term()
RemoveFromLeafSystem();
RemoveFromAimEntsList();
if ( m_hScriptInstance )
{
g_pScriptVM->RemoveInstance( m_hScriptInstance );
m_hScriptInstance = NULL;
}
}
@ -6442,6 +6460,26 @@ int C_BaseEntity::GetCreationTick() const
return m_nCreationTick;
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
HSCRIPT C_BaseEntity::GetScriptInstance()
{
if (!m_hScriptInstance)
{
if (m_iszScriptId == NULL_STRING)
{
char* szName = (char*)stackalloc(1024);
g_pScriptVM->GenerateUniqueKey((m_iName != NULL_STRING) ? STRING(GetEntityName()) : GetClassname(), szName, 1024);
m_iszScriptId = AllocPooledString(szName);
}
m_hScriptInstance = g_pScriptVM->RegisterInstance(GetScriptDesc(), this);
g_pScriptVM->SetInstanceUniqeId(m_hScriptInstance, STRING(m_iszScriptId));
}
return m_hScriptInstance;
}
//------------------------------------------------------------------------------
void CC_CL_Find_Ent( const CCommand& args )
{

View File

@ -36,6 +36,9 @@
#include "toolframework/itoolentity.h"
#include "tier0/threadtools.h"
#include "vscript/ivscript.h"
#include "vscript_shared.h"
class C_Team;
class IPhysicsObject;
class IClientVehicle;
@ -183,6 +186,8 @@ public:
DECLARE_DATADESC();
DECLARE_CLIENTCLASS();
DECLARE_PREDICTABLE();
// script description
DECLARE_ENT_SCRIPTDESC();
C_BaseEntity();
virtual ~C_BaseEntity();
@ -256,6 +261,11 @@ public:
string_t m_iClassname;
HSCRIPT GetScriptInstance();
HSCRIPT m_hScriptInstance;
string_t m_iszScriptId;
// IClientUnknown overrides.
public:
@ -1119,6 +1129,10 @@ public:
virtual int GetBody() { return 0; }
virtual int GetSkin() { return 0; }
const Vector& ScriptGetForward(void) { static Vector vecForward; GetVectors(&vecForward, NULL, NULL); return vecForward; }
const Vector& ScriptGetLeft(void) { static Vector vecLeft; GetVectors(NULL, &vecLeft, NULL); return vecLeft; }
const Vector& ScriptGetUp(void) { static Vector vecUp; GetVectors(NULL, NULL, &vecUp); return vecUp; }
// Stubs on client
void NetworkStateManualMode( bool activate ) { }
void NetworkStateChanged() { }
@ -1266,6 +1280,7 @@ public:
void SetRenderMode( RenderMode_t nRenderMode, bool bForceUpdate = false );
RenderMode_t GetRenderMode() const;
const char* GetEntityName();
public:
// Determine what entity this corresponds to
@ -1648,6 +1663,8 @@ private:
// The owner!
EHANDLE m_hOwnerEntity;
EHANDLE m_hEffectEntity;
char m_iName[MAX_PATH];
// This is a random seed used by the networking code to allow client - side prediction code
// randon number generators to spit out the same random numbers on both sides for a particular
@ -2203,6 +2220,12 @@ inline bool C_BaseEntity::ShouldRecordInTools() const
#endif
}
inline const char *C_BaseEntity::GetEntityName()
{
return m_iName;
}
C_BaseEntity *CreateEntityByName( const char *className );
#endif // C_BASEENTITY_H

View File

@ -1480,7 +1480,7 @@ bool C_BaseFlex::ClearSceneEvent( CSceneEventInfo *info, bool fastKill, bool can
// expression -
// duration -
//-----------------------------------------------------------------------------
void C_BaseFlex::AddSceneEvent( CChoreoScene *scene, CChoreoEvent *event, CBaseEntity *pTarget, bool bClientSide )
void C_BaseFlex::AddSceneEvent( CChoreoScene *scene, CChoreoEvent *event, CBaseEntity *pTarget, bool bClientSide, C_SceneEntity* pSceneEntity)
{
if ( !scene || !event )
{
@ -1505,6 +1505,7 @@ void C_BaseFlex::AddSceneEvent( CChoreoScene *scene, CChoreoEvent *event, CBaseE
info.m_hTarget = pTarget;
info.m_bStarted = false;
info.m_bClientSide = bClientSide;
info.m_hSceneEntity = pSceneEntity;
if (StartSceneEvent( &info, scene, event, actor, pTarget ))
{

View File

@ -214,7 +214,7 @@ public:
virtual bool ClearSceneEvent( CSceneEventInfo *info, bool fastKill, bool canceled );
// Add the event to the queue for this actor
void AddSceneEvent( CChoreoScene *scene, CChoreoEvent *event, C_BaseEntity *pTarget = NULL, bool bClientSide = false );
void AddSceneEvent( CChoreoScene *scene, CChoreoEvent *event, C_BaseEntity *pTarget = NULL, bool bClientSide = false, C_SceneEntity* pSceneEntity = NULL);
// Remove the event from the queue for this actor
void RemoveSceneEvent( CChoreoScene *scene, CChoreoEvent *event, bool fastKill );

View File

@ -674,7 +674,7 @@ void C_SceneEntity::DispatchStartSpeak( CChoreoScene *scene, C_BaseFlex *actor,
es.m_pSoundName = event->GetParameters();
EmitSound( filter, actor->entindex(), es );
actor->AddSceneEvent( scene, event, NULL, IsClientOnly() );
actor->AddSceneEvent( scene, event, NULL, IsClientOnly(), this );
// Close captioning only on master token no matter what...
if ( event->GetCloseCaptionType() == CChoreoEvent::CC_MASTER )
@ -964,7 +964,7 @@ void C_SceneEntity::UnloadScene( void )
//-----------------------------------------------------------------------------
void C_SceneEntity::DispatchStartFlexAnimation( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event )
{
actor->AddSceneEvent( scene, event, NULL, IsClientOnly() );
actor->AddSceneEvent( scene, event, NULL, IsClientOnly(), this );
}
//-----------------------------------------------------------------------------
@ -984,7 +984,7 @@ void C_SceneEntity::DispatchEndFlexAnimation( CChoreoScene *scene, C_BaseFlex *a
//-----------------------------------------------------------------------------
void C_SceneEntity::DispatchStartExpression( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event )
{
actor->AddSceneEvent( scene, event, NULL, IsClientOnly() );
actor->AddSceneEvent( scene, event, NULL, IsClientOnly(), this );
}
//-----------------------------------------------------------------------------
@ -1008,7 +1008,7 @@ void C_SceneEntity::DispatchStartGesture( CChoreoScene *scene, C_BaseFlex *actor
if ( !Q_stricmp( event->GetName(), "NULL" ) )
return;
actor->AddSceneEvent( scene, event, NULL, IsClientOnly() );
actor->AddSceneEvent( scene, event, NULL, IsClientOnly(), this );
}
//-----------------------------------------------------------------------------
@ -1023,7 +1023,7 @@ void C_SceneEntity::DispatchProcessGesture( CChoreoScene *scene, C_BaseFlex *act
return;
actor->RemoveSceneEvent( scene, event, false );
actor->AddSceneEvent( scene, event, NULL, IsClientOnly() );
actor->AddSceneEvent( scene, event, NULL, IsClientOnly(), this );
}
//-----------------------------------------------------------------------------
@ -1046,7 +1046,7 @@ void C_SceneEntity::DispatchEndGesture( CChoreoScene *scene, C_BaseFlex *actor,
//-----------------------------------------------------------------------------
void C_SceneEntity::DispatchStartSequence( CChoreoScene *scene, CBaseFlex *actor, CChoreoEvent *event )
{
actor->AddSceneEvent( scene, event, NULL, IsClientOnly() );
actor->AddSceneEvent( scene, event, NULL, IsClientOnly(), this );
}
//-----------------------------------------------------------------------------
@ -1056,7 +1056,7 @@ void C_SceneEntity::DispatchStartSequence( CChoreoScene *scene, CBaseFlex *actor
void C_SceneEntity::DispatchProcessSequence( CChoreoScene *scene, CBaseFlex *actor, CChoreoEvent *event )
{
actor->RemoveSceneEvent( scene, event, false );
actor->AddSceneEvent( scene, event, NULL, IsClientOnly() );
actor->AddSceneEvent( scene, event, NULL, IsClientOnly(), this );
}
//-----------------------------------------------------------------------------

View File

@ -223,6 +223,8 @@ IReplaySystem *g_pReplay = NULL;
IVEngineServer *serverengine = NULL;
#endif
IScriptManager *scriptmanager = NULL;
IHaptics* haptics = NULL;// NVNT haptics system interface singleton
//=============================================================================
@ -964,6 +966,11 @@ int CHLClient::Init( CreateInterfaceFn appSystemFactory, CreateInterfaceFn physi
if (!g_pMatSystemSurface)
return false;
if ( !CommandLine()->CheckParm( "-noscripting") )
{
scriptmanager = (IScriptManager *)appSystemFactory( VSCRIPT_INTERFACE_VERSION, NULL );
}
#ifdef WORKSHOP_IMPORT_ENABLED
if ( !ConnectDataModel( appSystemFactory ) )
return false;

View File

@ -493,6 +493,11 @@ $Project
$File "viewrender.cpp"
$File "$SRCDIR\game\shared\voice_banmgr.cpp"
$File "$SRCDIR\game\shared\voice_status.cpp"
$File "vscript_client.cpp"
$File "vscript_client.h"
$File "vscript_client.nut"
$File "$SRCDIR\game\shared\vscript_shared.cpp"
$File "$SRCDIR\game\shared\vscript_shared.h"
$File "warp_overlay.cpp"
$File "WaterLODMaterialProxy.cpp"
$File "$SRCDIR\game\shared\weapon_parse.cpp"

View File

@ -0,0 +1,190 @@
//========== Copyright © 2008, Valve Corporation, All rights reserved. ========
//
// Purpose:
//
//=============================================================================
#include "cbase.h"
#include "vscript_client.h"
#include "icommandline.h"
#include "tier1/utlbuffer.h"
#include "tier1/fmtstr.h"
#include "filesystem.h"
#include "characterset.h"
#include "isaverestore.h"
#include "gamerules.h"
#ifdef _WIN32
//#include "vscript_client_nut.h"
#endif
extern IScriptManager *scriptmanager;
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
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
static float Time()
{
return gpGlobals->curtime;
}
static const char *GetMapName()
{
return engine->GetLevelName();
}
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;
}
bool VScriptClientInit()
{
VMPROF_START
if( scriptmanager != NULL )
{
ScriptLanguage_t scriptLanguage = SL_DEFAULT;
char const *pszScriptLanguage;
if ( CommandLine()->CheckParm( "-scriptlang", &pszScriptLanguage ) )
{
if( !Q_stricmp(pszScriptLanguage, "gamemonkey") )
{
scriptLanguage = SL_GAMEMONKEY;
}
else if( !Q_stricmp(pszScriptLanguage, "squirrel") )
{
scriptLanguage = SL_SQUIRREL;
}
else if( !Q_stricmp(pszScriptLanguage, "python") )
{
scriptLanguage = SL_PYTHON;
}
else
{
DevWarning("-scriptlang does not recognize a language named '%s'. virtual machine did NOT start.\n", pszScriptLanguage );
scriptLanguage = SL_NONE;
}
}
if( scriptLanguage != SL_NONE )
{
if ( g_pScriptVM == NULL )
g_pScriptVM = scriptmanager->CreateVM( scriptLanguage );
if( g_pScriptVM )
{
Log( "VSCRIPT: Started VScript virtual machine using script language '%s'\n", g_pScriptVM->GetLanguageName() );
ScriptRegisterFunction( g_pScriptVM, GetMapName, "Get the name of the map.");
ScriptRegisterFunction( g_pScriptVM, Time, "Get the current server time" );
ScriptRegisterFunction( g_pScriptVM, DoIncludeScript, "Execute a script (internal)" );
if ( GameRules() )
{
GameRules()->RegisterScriptFunctions();
}
//g_pScriptVM->RegisterInstance( &g_ScriptEntityIterator, "Entities" );
if ( scriptLanguage == SL_SQUIRREL )
{
//g_pScriptVM->Run( g_Script_vscript_client );
}
VScriptRunScript( "mapspawn", false );
VMPROF_SHOW( pszScriptLanguage, "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 VScriptClientTerm()
{
if( g_pScriptVM != NULL )
{
if( g_pScriptVM )
{
scriptmanager->DestroyVM( g_pScriptVM );
g_pScriptVM = NULL;
}
}
}
class CVScriptGameSystem : public CAutoGameSystemPerFrame
{
public:
// Inherited from IAutoServerSystem
virtual void LevelInitPreEntity( void )
{
m_bAllowEntityCreationInScripts = true;
VScriptClientInit();
}
virtual void LevelInitPostEntity( void )
{
m_bAllowEntityCreationInScripts = false;
}
virtual void LevelShutdownPostEntity( void )
{
VScriptClientTerm();
}
virtual void FrameUpdatePostEntityThink()
{
if ( g_pScriptVM )
g_pScriptVM->Frame( gpGlobals->frametime );
}
bool m_bAllowEntityCreationInScripts;
};
CVScriptGameSystem g_VScriptGameSystem;
bool IsEntityCreationAllowedInScripts( void )
{
return g_VScriptGameSystem.m_bAllowEntityCreationInScripts;
}

View File

@ -0,0 +1,22 @@
//========== Copyright © 2008, Valve Corporation, All rights reserved. ========
//
// Purpose:
//
//=============================================================================
#ifndef VSCRIPT_SERVER_H
#define VSCRIPT_SERVER_H
#include "vscript/ivscript.h"
#include "vscript_shared.h"
#if defined( _WIN32 )
#pragma once
#endif
extern IScriptVM * g_pScriptVM;
// Only allow scripts to create entities during map initialization
bool IsEntityCreationAllowedInScripts( void );
#endif // VSCRIPT_SERVER_H

View File

@ -0,0 +1,19 @@
//========== Copyright © 2008, Valve Corporation, All rights reserved. ========
//
// Purpose:
//
//=============================================================================
function UniqueString( string = "" )
{
return DoUniqueString( string.tostring() );
}
function IncludeScript( name, scope = null )
{
if ( scope == null )
{
scope = this;
}
return ::DoIncludeScript( name, scope );
}

View File

@ -282,6 +282,14 @@ IMPLEMENT_SERVERCLASS_ST(CBaseAnimating, DT_BaseAnimating)
END_SEND_TABLE()
BEGIN_ENT_SCRIPTDESC( CBaseAnimating, CBaseEntity, "Animating models" )
DEFINE_SCRIPTFUNC( LookupAttachment, "Get the named attachement id" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetAttachmentOrigin, "GetAttachmentOrigin", "Get the attachement id's origin vector" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetAttachmentAngles, "GetAttachmentAngles", "Get the attachement id's angles as a p,y,r vector" )
DEFINE_SCRIPTFUNC( IsSequenceFinished, "Ask whether the main sequence is done playing" )
DEFINE_SCRIPTFUNC( SetBodygroup, "Sets a bodygroup")
END_SCRIPTDESC();
CBaseAnimating::CBaseAnimating()
{
@ -2117,6 +2125,35 @@ bool CBaseAnimating::GetAttachment( int iAttachment, Vector &absOrigin, Vector *
return bRet;
}
//-----------------------------------------------------------------------------
// Purpose: Returns the world location and world angles of an attachment to vscript caller
// Input : attachment name
// Output : location and angles
//-----------------------------------------------------------------------------
const Vector& CBaseAnimating::ScriptGetAttachmentOrigin( int iAttachment )
{
static Vector absOrigin;
static QAngle qa;
CBaseAnimating::GetAttachment( iAttachment, absOrigin, qa );
return absOrigin;
}
const Vector& CBaseAnimating::ScriptGetAttachmentAngles( int iAttachment )
{
static Vector absOrigin;
static Vector absAngles;
static QAngle qa;
CBaseAnimating::GetAttachment( iAttachment, absOrigin, qa );
absAngles.x = qa.x;
absAngles.y = qa.y;
absAngles.z = qa.z;
return absAngles;
}
//-----------------------------------------------------------------------------
// Returns the attachment in local space

View File

@ -44,6 +44,7 @@ public:
DECLARE_DATADESC();
DECLARE_SERVERCLASS();
DECLARE_ENT_SCRIPTDESC();
virtual void SetModel( const char *szModelName );
virtual void Activate();
@ -186,6 +187,8 @@ public:
bool GetAttachment( int iAttachment, Vector &absOrigin, QAngle &absAngles );
int GetAttachmentBone( int iAttachment );
virtual bool GetAttachment( int iAttachment, matrix3x4_t &attachmentToWorld );
const Vector& ScriptGetAttachmentOrigin(int iAttachment);
const Vector& ScriptGetAttachmentAngles(int iAttachment);
// These return the attachment in the space of the entity
bool GetAttachmentLocal( const char *szName, Vector &origin, QAngle &angles );

View File

@ -101,6 +101,9 @@ bool CBaseEntity::s_bAbsQueriesValid = true;
ConVar sv_netvisdist( "sv_netvisdist", "10000", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY, "Test networking visibility distance" );
ConVar sv_script_think_interval("sv_script_think_interval", "0.1");
// This table encodes edict data.
void SendProxy_AnimTime( const SendProp *pProp, const void *pStruct, const void *pVarData, DVariant *pOut, int iElement, int objectID )
{
@ -291,6 +294,8 @@ IMPLEMENT_SERVERCLASS_ST_NOBASE( CBaseEntity, DT_BaseEntity )
SendPropEHandle (SENDINFO_NAME(m_hMoveParent, moveparent)),
SendPropInt (SENDINFO(m_iParentAttachment), NUM_PARENTATTACHMENT_BITS, SPROP_UNSIGNED),
SendPropStringT( SENDINFO( m_iName ) ),
SendPropInt (SENDINFO_NAME( m_MoveType, movetype ), MOVETYPE_MAX_BITS, SPROP_UNSIGNED ),
SendPropInt (SENDINFO_NAME( m_MoveCollide, movecollide ), MOVECOLLIDE_MAX_BITS, SPROP_UNSIGNED ),
#if PREDICTION_ERROR_CHECK_LEVEL > 1
@ -1313,6 +1318,19 @@ void CBaseEntity::FireNamedOutput( const char *pszOutput, variant_t variant, CBa
if ( pszOutput == NULL )
return;
CBaseEntityOutput *pOutput = FindNamedOutput( pszOutput );
if ( pOutput )
{
pOutput->FireOutput( variant, pActivator, pCaller, flDelay );
return;
}
}
CBaseEntityOutput *CBaseEntity::FindNamedOutput( const char *pszOutput )
{
if ( pszOutput == NULL )
return NULL;
datamap_t *dmap = GetDataDescMap();
while ( dmap )
{
@ -1322,17 +1340,16 @@ void CBaseEntity::FireNamedOutput( const char *pszOutput, variant_t variant, CBa
typedescription_t *dataDesc = &dmap->dataDesc[i];
if ( ( dataDesc->fieldType == FIELD_CUSTOM ) && ( dataDesc->flags & FTYPEDESC_OUTPUT ) )
{
CBaseEntityOutput *pOutput = ( CBaseEntityOutput * )( ( int )this + ( int )dataDesc->fieldOffset[0] );
CBaseEntityOutput *pOutput = ( CBaseEntityOutput * )( ( int )this + ( int )dataDesc->fieldOffset );
if ( !Q_stricmp( dataDesc->externalName, pszOutput ) )
{
pOutput->FireOutput( variant, pActivator, pCaller, flDelay );
return;
return pOutput;
}
}
}
dmap = dmap->baseMap;
}
return NULL;
}
void CBaseEntity::Activate( void )
@ -1822,6 +1839,12 @@ BEGIN_DATADESC_NO_BASE( CBaseEntity )
DEFINE_FIELD( m_flSimulationTime, FIELD_TIME ),
DEFINE_FIELD( m_nLastThinkTick, FIELD_TICK ),
DEFINE_FIELD(m_iszScriptId, FIELD_STRING),
// m_ScriptScope;
// m_hScriptInstance;
DEFINE_KEYFIELD(m_iszVScripts, FIELD_STRING, "vscripts"),
DEFINE_KEYFIELD(m_iszScriptThinkFunction, FIELD_STRING, "thinkfunction"),
DEFINE_KEYFIELD( m_nNextThinkTick, FIELD_TICK, "nextthink" ),
DEFINE_KEYFIELD( m_fEffects, FIELD_INTEGER, "effects" ),
DEFINE_KEYFIELD( m_clrRender, FIELD_COLOR32, "rendercolor" ),
@ -2004,6 +2027,10 @@ BEGIN_DATADESC_NO_BASE( CBaseEntity )
DEFINE_INPUTFUNC( FIELD_STRING, "FireUser4", InputFireUser4 ),
#endif
DEFINE_INPUTFUNC(FIELD_STRING, "RunScriptFile", InputRunScriptFile),
DEFINE_INPUTFUNC(FIELD_STRING, "RunScriptCode", InputRunScript),
DEFINE_INPUTFUNC(FIELD_STRING, "CallScriptFunction", InputCallScriptFunction),
#ifdef MAPBASE
DEFINE_OUTPUT( m_OutUser1, "OutUser1" ),
DEFINE_OUTPUT( m_OutUser2, "OutUser2" ),
@ -2081,6 +2108,7 @@ BEGIN_DATADESC_NO_BASE( CBaseEntity )
DEFINE_FUNCTION( SUB_Vanish ),
DEFINE_FUNCTION( SUB_CallUseToggle ),
DEFINE_THINKFUNC( ShadowCastDistThink ),
DEFINE_THINKFUNC( ScriptThink ),
#ifdef MAPBASE
DEFINE_FUNCTION( SUB_RemoveWhenNotVisible ),
@ -2097,6 +2125,81 @@ BEGIN_DATADESC_NO_BASE( CBaseEntity )
END_DATADESC()
BEGIN_ENT_SCRIPTDESC_ROOT( CBaseEntity, "Root class of all server-side entities" )
DEFINE_SCRIPT_INSTANCE_HELPER( &g_BaseEntityScriptInstanceHelper )
DEFINE_SCRIPTFUNC_NAMED( ConnectOutputToScript, "ConnectOutput", "Adds an I/O connection that will call the named function when the specified output fires" )
DEFINE_SCRIPTFUNC_NAMED( DisconnectOutputFromScript, "DisconnectOutput", "Removes a connected script function from an I/O event." )
DEFINE_SCRIPTFUNC( GetHealth, "" )
DEFINE_SCRIPTFUNC( SetHealth, "" )
DEFINE_SCRIPTFUNC( GetMaxHealth, "" )
DEFINE_SCRIPTFUNC( SetMaxHealth, "" )
DEFINE_SCRIPTFUNC( SetModel, "" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetModelName, "GetModelName", "Returns the name of the model" )
DEFINE_SCRIPTFUNC_NAMED( ScriptEmitSound, "EmitSound", "Plays a sound from this entity." )
DEFINE_SCRIPTFUNC_NAMED( VScriptPrecacheScriptSound, "PrecacheSoundScript", "Precache a sound for later playing." )
DEFINE_SCRIPTFUNC_NAMED( ScriptSoundDuration, "GetSoundDuration", "Returns float duration of the sound. Takes soundname and optional actormodelname.")
DEFINE_SCRIPTFUNC( GetClassname, "" )
DEFINE_SCRIPTFUNC_NAMED( GetEntityNameAsCStr, "GetName", "" )
DEFINE_SCRIPTFUNC( GetPreTemplateName, "Get the entity name stripped of template unique decoration" )
DEFINE_SCRIPTFUNC_NAMED( GetAbsOrigin, "GetOrigin", "" )
DEFINE_SCRIPTFUNC( SetAbsOrigin, "SetAbsOrigin" )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetOrigin, "SetOrigin", "" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetForward, "GetForwardVector", "Get the forward vector of the entity" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetLeft, "GetLeftVector", "Get the left vector of the entity" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetUp, "GetUpVector", "Get the up vector of the entity" )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetForward, "SetForwardVector", "Set the orientation of the entity to have this forward vector" )
DEFINE_SCRIPTFUNC_NAMED( GetAbsVelocity, "GetVelocity", "" )
DEFINE_SCRIPTFUNC_NAMED( SetAbsVelocity, "SetVelocity", "" )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetLocalAngularVelocity, "SetAngularVelocity", "Set the local angular velocity - takes float pitch,yaw,roll velocities" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetLocalAngularVelocity, "GetAngularVelocity", "Get the local angular velocity - returns a vector of pitch,yaw,roll" )
DEFINE_SCRIPTFUNC_NAMED( WorldSpaceCenter, "GetCenter", "Get vector to center of object - absolute coords")
DEFINE_SCRIPTFUNC_NAMED( ScriptEyePosition, "EyePosition", "Get vector to eye position - absolute coords")
DEFINE_SCRIPTFUNC_NAMED( ScriptSetAngles, "SetAngles", "Set entity pitch, yaw, roll")
DEFINE_SCRIPTFUNC_NAMED( ScriptGetAngles, "GetAngles", "Get entity pitch, yaw, roll as a vector")
DEFINE_SCRIPTFUNC_NAMED( ScriptSetSize, "SetSize", "" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetBoundingMins, "GetBoundingMins", "Get a vector containing min bounds, centered on object")
DEFINE_SCRIPTFUNC_NAMED( ScriptGetBoundingMaxs, "GetBoundingMaxs", "Get a vector containing max bounds, centered on object")
DEFINE_SCRIPTFUNC_NAMED( ScriptUtilRemove, "Destroy", "" )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetOwner, "SetOwner", "" )
DEFINE_SCRIPTFUNC_NAMED( GetTeamNumber, "GetTeam", "" )
DEFINE_SCRIPTFUNC_NAMED( ChangeTeam, "SetTeam", "" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetMoveParent, "GetMoveParent", "If in hierarchy, retrieves the entity's parent" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetRootMoveParent, "GetRootMoveParent", "If in hierarchy, walks up the hierarchy to find the root parent" )
DEFINE_SCRIPTFUNC_NAMED( ScriptFirstMoveChild, "FirstMoveChild", "" )
DEFINE_SCRIPTFUNC_NAMED( ScriptNextMovePeer, "NextMovePeer", "" )
DEFINE_SCRIPTFUNC_NAMED( KeyValueFromString, "__KeyValueFromString", SCRIPT_HIDE )
DEFINE_SCRIPTFUNC_NAMED( KeyValueFromFloat, "__KeyValueFromFloat", SCRIPT_HIDE )
DEFINE_SCRIPTFUNC_NAMED( KeyValueFromInt, "__KeyValueFromInt", SCRIPT_HIDE )
DEFINE_SCRIPTFUNC_NAMED( KeyValueFromVector, "__KeyValueFromVector", SCRIPT_HIDE )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetModelKeyValues, "GetModelKeyValues", "Get a KeyValue class instance on this entity's model")
DEFINE_SCRIPTFUNC( ValidateScriptScope, "Ensure that an entity's script scope has been created" )
DEFINE_SCRIPTFUNC( GetScriptScope, "Retrieve the script-side data associated with an entity" )
DEFINE_SCRIPTFUNC( GetScriptId, "Retrieve the unique identifier used to refer to the entity within the scripting system" )
DEFINE_SCRIPTFUNC_NAMED( GetScriptOwnerEntity, "GetOwner", "Gets this entity's owner" )
DEFINE_SCRIPTFUNC_NAMED( SetScriptOwnerEntity, "SetOwner", "Sets this entity's owner" )
DEFINE_SCRIPTFUNC( entindex, "" )
END_SCRIPTDESC();
// For code error checking
extern bool g_bReceivedChainedUpdateOnRemove;
@ -2196,6 +2299,12 @@ void CBaseEntity::UpdateOnRemove( void )
modelinfo->ReleaseDynamicModel( m_nModelIndex ); // no-op if not dynamic
m_nModelIndex = -1;
}
if ( m_hScriptInstance )
{
g_pScriptVM->RemoveInstance( m_hScriptInstance );
m_hScriptInstance = NULL;
}
}
//-----------------------------------------------------------------------------
@ -3925,9 +4034,9 @@ const char *CBaseEntity::GetDebugName(void)
if ( this == NULL )
return "<<null>>";
if ( m_iName != NULL_STRING )
if ( m_iName.Get() != NULL_STRING )
{
return STRING(m_iName);
return STRING(m_iName.Get());
}
else
{
@ -4108,7 +4217,7 @@ bool CBaseEntity::AcceptInput( const char *szInputName, CBaseEntity *pActivator,
// mapper debug message
if (pCaller != NULL)
{
Q_snprintf( szBuffer, sizeof(szBuffer), "(%0.2f) input %s: %s.%s(%s)\n", gpGlobals->curtime, STRING(pCaller->m_iName), GetDebugName(), szInputName, Value.String() );
Q_snprintf( szBuffer, sizeof(szBuffer), "(%0.2f) input %s: %s.%s(%s)\n", gpGlobals->curtime, STRING(pCaller->m_iName.Get()), GetDebugName(), szInputName, Value.String() );
}
else
{
@ -4155,7 +4264,7 @@ bool CBaseEntity::AcceptInput( const char *szInputName, CBaseEntity *pActivator,
Warning( "!! ERROR: bad input/output link:\n!! Unable to convert value \"%s\" from %s (%s) to field type %i\n!! Target Entity: %s (%s), Input: %s\n",
Value.GetDebug(),
( pCaller != NULL ) ? STRING(pCaller->m_iClassname) : "<null>",
( pCaller != NULL ) ? STRING(pCaller->m_iName) : "<null>",
( pCaller != NULL ) ? STRING(pCaller->m_iName.Get()) : "<null>",
dmap->dataDesc[i].fieldType,
STRING(m_iClassname), GetDebugName(), szInputName );
return false;
@ -4168,7 +4277,7 @@ bool CBaseEntity::AcceptInput( const char *szInputName, CBaseEntity *pActivator,
Warning( "!! ERROR: bad input/output link:\n!! %s(%s,%s) doesn't match type from %s(%s)\n",
STRING(m_iClassname), GetDebugName(), szInputName,
( pCaller != NULL ) ? STRING(pCaller->m_iClassname) : "<null>",
( pCaller != NULL ) ? STRING(pCaller->m_iName) : "<null>" );
( pCaller != NULL ) ? STRING(pCaller->m_iName.Get()) : "<null>" );
return false;
}
#endif
@ -4187,7 +4296,37 @@ bool CBaseEntity::AcceptInput( const char *szInputName, CBaseEntity *pActivator,
data.value = Value;
data.nOutputID = outputID;
(this->*pfnInput)( data );
// Now, see if there's a function named Input<Name of Input> in this entity's script file.
// If so, execute it and let it decide whether to allow the default behavior to also execute.
bool bCallInputFunc = true; // Always assume default behavior (do call the input function)
ScriptVariant_t functionReturn;
if ( m_ScriptScope.IsInitialized() )
{
char szScriptFunctionName[255];
Q_strcpy( szScriptFunctionName, "Input" );
Q_strcat( szScriptFunctionName, szInputName, 255 );
g_pScriptVM->SetValue( "activator", ( pActivator ) ? ScriptVariant_t( pActivator->GetScriptInstance() ) : SCRIPT_VARIANT_NULL );
g_pScriptVM->SetValue( "caller", ( pCaller ) ? ScriptVariant_t( pCaller->GetScriptInstance() ) : SCRIPT_VARIANT_NULL );
if( CallScriptFunction( szScriptFunctionName, &functionReturn ) )
{
bCallInputFunc = functionReturn.m_bool;
}
}
if( bCallInputFunc )
{
(this->*pfnInput)( data );
}
if ( m_ScriptScope.IsInitialized() )
{
g_pScriptVM->ClearValue( "activator" );
g_pScriptVM->ClearValue( "caller" );
}
}
else if ( dmap->dataDesc[i].flags & FTYPEDESC_KEY )
{
@ -4210,7 +4349,7 @@ bool CBaseEntity::AcceptInput( const char *szInputName, CBaseEntity *pActivator,
}
}
DevMsg( 2, "unhandled input: (%s) -> (%s,%s)\n", szInputName, STRING(m_iClassname), GetDebugName()/*,", from (%s,%s)" STRING(pCaller->m_iClassname), STRING(pCaller->m_iName)*/ );
DevMsg( 2, "unhandled input: (%s) -> (%s,%s)\n", szInputName, STRING(m_iClassname), GetDebugName()/*,", from (%s,%s)" STRING(pCaller->m_iClassname), STRING(pCaller->m_iName.Get())*/ );
return false;
}
@ -5300,6 +5439,36 @@ void CC_Ent_Name( const CCommand& args )
}
static ConCommand ent_name("ent_name", CC_Ent_Name, 0, FCVAR_CHEAT);
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void DumpScriptScope(CBasePlayer* pPlayer, const char* name)
{
CBaseEntity* pEntity = NULL;
while ((pEntity = GetNextCommandEntity(pPlayer, name, pEntity)) != NULL)
{
if (pEntity->m_ScriptScope.IsInitialized())
{
Msg("----Script Dump for entity %s\n", pEntity->GetDebugName());
HSCRIPT hDumpScopeFunc = g_pScriptVM->LookupFunction("__DumpScope");
g_pScriptVM->Call(hDumpScopeFunc, NULL, true, NULL, 1, (HSCRIPT)pEntity->m_ScriptScope);
Msg("----End Script Dump\n");
}
else
{
DevWarning("ent_script_dump: Entity %s has no script scope!\n", pEntity->GetDebugName());
}
}
}
//------------------------------------------------------------------------------
void CC_Ent_Script_Dump( const CCommand& args )
{
DumpScriptScope(UTIL_GetCommandClient(),args[1]);
}
static ConCommand ent_script_dump("ent_script_dump", CC_Ent_Script_Dump, "Dumps the names and values of this entity's script scope to the console\n\tArguments: {entity_name} / {class_name} / no argument picks what player is looking at ", FCVAR_CHEAT);
//------------------------------------------------------------------------------
#ifdef MAPBASE
class CEntTextAutoCompletionFunctor : public ICommandCallback, public ICommandCompletionCallback
@ -7223,7 +7392,6 @@ void CBaseEntity::InputPassRandomUser( inputdata_t& inputdata )
}
#endif
#ifdef MAPBASE
//-----------------------------------------------------------------------------
// Purpose: Sets the entity's targetname.
@ -7820,6 +7988,256 @@ void CBaseEntity::InputSetThinkNull( inputdata_t& inputdata )
#endif
//---------------------------------------------------------
// Use the string as the filename of a script file
// that should be loaded from disk, compiled, and run.
//---------------------------------------------------------
void CBaseEntity::InputRunScriptFile(inputdata_t& inputdata)
{
RunScriptFile(inputdata.value.String());
}
//---------------------------------------------------------
// Send the string to the VM as source code and execute it
//---------------------------------------------------------
void CBaseEntity::InputRunScript(inputdata_t& inputdata)
{
RunScript(inputdata.value.String(), "InputRunScript");
}
//---------------------------------------------------------
// Make an explicit function call.
//---------------------------------------------------------
void CBaseEntity::InputCallScriptFunction(inputdata_t& inputdata)
{
CallScriptFunction(inputdata.value.String(), NULL);
}
// #define VMPROFILE // define to profile vscript calls
#ifdef VMPROFILE
float g_debugCumulativeTime = 0.0;
float g_debugCounter = 0;
#define START_VMPROFILE float debugStartTime = Plat_FloatTime();
#define UPDATE_VMPROFILE \
g_debugCumulativeTime += Plat_FloatTime() - debugStartTime; \
g_debugCounter++; \
if ( g_debugCounter >= 500 ) \
{ \
DevMsg("***VSCRIPT PROFILE***: %s %s: %6.4f milliseconds\n", "500 vscript function calls", "", g_debugCumulativeTime*1000.0 ); \
g_debugCounter = 0; \
g_debugCumulativeTime = 0.0; \
} \
#else
#define START_VMPROFILE
#define UPDATE_VMPROFILE
#endif // VMPROFILE
//-----------------------------------------------------------------------------
// Returns true if the function was located and called. false otherwise.
// NOTE: Assumes the function takes no parameters at the moment.
//-----------------------------------------------------------------------------
bool CBaseEntity::CallScriptFunction(const char* pFunctionName, ScriptVariant_t* pFunctionReturn)
{
START_VMPROFILE
if (!ValidateScriptScope())
{
DevMsg("\n***\nFAILED to create private ScriptScope. ABORTING script\n***\n");
return false;
}
HSCRIPT hFunc = m_ScriptScope.LookupFunction(pFunctionName);
if (hFunc)
{
m_ScriptScope.Call(hFunc, pFunctionReturn);
m_ScriptScope.ReleaseFunction(hFunc);
UPDATE_VMPROFILE
return true;
}
return false;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CBaseEntity::ConnectOutputToScript(const char* pszOutput, const char* pszScriptFunc)
{
CBaseEntityOutput* pOutput = FindNamedOutput(pszOutput);
if (!pOutput)
{
DevMsg(2, "Script failed to find output \"%s\"\n", pszOutput);
return;
}
string_t iszSelf = AllocPooledString("!self"); // @TODO: cache this [4/25/2008 tom]
CEventAction* pAction = pOutput->GetActionList();
while (pAction)
{
if (pAction->m_iTarget == iszSelf &&
pAction->m_flDelay == 0 &&
pAction->m_nTimesToFire == EVENT_FIRE_ALWAYS &&
V_strcmp(STRING(pAction->m_iTargetInput), "CallScriptFunction") == 0 &&
V_strcmp(STRING(pAction->m_iParameter), pszScriptFunc) == 0)
{
return;
}
pAction = pAction->m_pNext;
}
pAction = new CEventAction(NULL);
pAction->m_iTarget = iszSelf;
pAction->m_iTargetInput = AllocPooledString("CallScriptFunction");
pAction->m_iParameter = AllocPooledString(pszScriptFunc);
pOutput->AddEventAction(pAction);
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CBaseEntity::DisconnectOutputFromScript(const char* pszOutput, const char* pszScriptFunc)
{
CBaseEntityOutput* pOutput = FindNamedOutput(pszOutput);
if (!pOutput)
{
DevMsg(2, "Script failed to find output \"%s\"\n", pszOutput);
return;
}
string_t iszSelf = AllocPooledString("!self"); // @TODO: cache this [4/25/2008 tom]
CEventAction* pAction = pOutput->GetActionList();
while (pAction)
{
if (pAction->m_iTarget == iszSelf &&
pAction->m_flDelay == 0 &&
pAction->m_nTimesToFire == EVENT_FIRE_ALWAYS &&
V_strcmp(STRING(pAction->m_iTargetInput), "CallScriptFunction") == 0 &&
V_strcmp(STRING(pAction->m_iParameter), pszScriptFunc) == 0)
{
pOutput->RemoveEventAction(pAction);
delete pAction;
return;
}
pAction = pAction->m_pNext;
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CBaseEntity::ScriptThink(void)
{
ScriptVariant_t varThinkRetVal;
if (CallScriptFunction(m_iszScriptThinkFunction.ToCStr(), &varThinkRetVal))
{
float flThinkFrequency = 0.0f;
if (!varThinkRetVal.AssignTo(&flThinkFrequency))
{
// use default think interval if script think function doesn't provide one
flThinkFrequency = sv_script_think_interval.GetFloat();
}
SetContextThink(&CBaseEntity::ScriptThink,
gpGlobals->curtime + flThinkFrequency, "ScriptThink");
}
else
{
DevWarning("%s FAILED to call script think function %s!\n", GetDebugName(), STRING(m_iszScriptThinkFunction));
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
const char* CBaseEntity::GetScriptId()
{
return STRING(m_iszScriptThinkFunction);
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT CBaseEntity::GetScriptScope()
{
return m_ScriptScope;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT CBaseEntity::ScriptGetMoveParent(void)
{
return ToHScript(GetMoveParent());
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT CBaseEntity::ScriptGetRootMoveParent()
{
return ToHScript(GetRootMoveParent());
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT CBaseEntity::ScriptFirstMoveChild(void)
{
return ToHScript(FirstMoveChild());
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT CBaseEntity::ScriptNextMovePeer(void)
{
return ToHScript(NextMovePeer());
}
//-----------------------------------------------------------------------------
// Purpose: Load, compile, and run a script file from disk.
// Input : *pScriptFile - The filename of the script file.
// bUseRootScope - If true, runs this script in the root scope, not
// in this entity's private scope.
//-----------------------------------------------------------------------------
bool CBaseEntity::RunScriptFile(const char* pScriptFile, bool bUseRootScope)
{
if (!ValidateScriptScope())
{
DevMsg("\n***\nFAILED to create private ScriptScope. ABORTING script\n***\n");
return false;
}
if (bUseRootScope)
{
return VScriptRunScript(pScriptFile);
}
else
{
return VScriptRunScript(pScriptFile, m_ScriptScope, true);
}
}
//-----------------------------------------------------------------------------
// Purpose: Compile and execute a discrete string of script source code
// Input : *pScriptText - A string containing script code to compile and run
//-----------------------------------------------------------------------------
bool CBaseEntity::RunScript(const char* pScriptText, const char* pDebugFilename)
{
if (!ValidateScriptScope())
{
DevMsg("\n***\nFAILED to create private ScriptScope. ABORTING script\n***\n");
return false;
}
if (m_ScriptScope.Run(pScriptText, pDebugFilename) == SCRIPT_ERROR)
{
DevWarning(" Entity %s encountered an error in RunScript()\n", GetDebugName());
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *contextName -
@ -8796,6 +9214,266 @@ void CBaseEntity::SetCollisionBoundsFromModel()
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
HSCRIPT CBaseEntity::GetScriptInstance()
{
if (!m_hScriptInstance)
{
if (m_iszScriptId == NULL_STRING)
{
char* szName = (char*)stackalloc(1024);
g_pScriptVM->GenerateUniqueKey((m_iName.Get() != NULL_STRING) ? STRING(GetEntityName()) : GetClassname(), szName, 1024);
m_iszScriptId = AllocPooledString(szName);
}
m_hScriptInstance = g_pScriptVM->RegisterInstance(GetScriptDesc(), this);
g_pScriptVM->SetInstanceUniqeId(m_hScriptInstance, STRING(m_iszScriptId));
}
return m_hScriptInstance;
}
//-----------------------------------------------------------------------------
// Using my edict, cook up a unique VScript scope that's private to me, and
// persistent.
//-----------------------------------------------------------------------------
bool CBaseEntity::ValidateScriptScope()
{
if (!m_ScriptScope.IsInitialized())
{
if (scriptmanager == NULL)
{
ExecuteOnce(DevMsg("Cannot execute script because scripting is disabled (-scripting)\n"));
return false;
}
if (g_pScriptVM == NULL)
{
ExecuteOnce(DevMsg(" Cannot execute script because there is no available VM\n"));
return false;
}
// Force instance creation
GetScriptInstance();
EHANDLE hThis;
hThis.Set(this);
bool bResult = m_ScriptScope.Init(STRING(m_iszScriptId));
if (!bResult)
{
DevMsg("%s couldn't create ScriptScope!\n", GetDebugName());
return false;
}
g_pScriptVM->SetValue(m_ScriptScope, "self", GetScriptInstance());
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Run all of the vscript files that are set in this entity's VSCRIPTS
// field in Hammer. The list is space-delimited.
//-----------------------------------------------------------------------------
void CBaseEntity::RunVScripts()
{
if (m_iszVScripts == NULL_STRING)
{
return;
}
ValidateScriptScope();
// All functions we want to have call chained instead of overwritten
// by other scripts in this entities list.
static const char* sCallChainFunctions[] =
{
"OnPostSpawn",
"Precache"
};
ScriptLanguage_t language = g_pScriptVM->GetLanguage();
// Make a call chainer for each in this entities scope
for (int j = 0; j < ARRAYSIZE(sCallChainFunctions); ++j)
{
if (language == SL_PYTHON)
{
// UNDONE - handle call chaining in python
;
}
else if (language == SL_SQUIRREL)
{
//TODO: For perf, this should be precompiled and the %s should be passed as a parameter
HSCRIPT hCreateChainScript = g_pScriptVM->CompileScript(CFmtStr("%sCallChain <- CSimpleCallChainer(\"%s\", self.GetScriptScope(), true)", sCallChainFunctions[j], sCallChainFunctions[j]));
g_pScriptVM->Run(hCreateChainScript, (HSCRIPT)m_ScriptScope);
}
}
char szScriptsList[255];
Q_strcpy(szScriptsList, STRING(m_iszVScripts));
CUtlStringList szScripts;
V_SplitString(szScriptsList, " ", szScripts);
for (int i = 0; i < szScripts.Count(); i++)
{
Log( "%s executing script: %s\n", GetDebugName(), szScripts[i]);
RunScriptFile(szScripts[i], IsWorld());
for (int j = 0; j < ARRAYSIZE(sCallChainFunctions); ++j)
{
if (language == SL_PYTHON)
{
// UNDONE - handle call chaining in python
;
}
else if (language == SL_SQUIRREL)
{
//TODO: For perf, this should be precompiled and the %s should be passed as a parameter.
HSCRIPT hRunPostScriptExecute = g_pScriptVM->CompileScript(CFmtStr("%sCallChain.PostScriptExecute()", sCallChainFunctions[j]));
g_pScriptVM->Run(hRunPostScriptExecute, (HSCRIPT)m_ScriptScope);
}
}
}
if (m_iszScriptThinkFunction != NULL_STRING)
{
SetContextThink(&CBaseEntity::ScriptThink, gpGlobals->curtime + sv_script_think_interval.GetFloat(), "ScriptThink");
}
}
//--------------------------------------------------------------------------------------------------
// This is called during entity spawning and after restore to allow scripts to precache any
// resources they need.
//--------------------------------------------------------------------------------------------------
void CBaseEntity::RunPrecacheScripts(void)
{
if (m_iszVScripts == NULL_STRING)
{
return;
}
HSCRIPT hScriptPrecache = m_ScriptScope.LookupFunction("DispatchPrecache");
if (hScriptPrecache)
{
g_pScriptVM->Call(hScriptPrecache, m_ScriptScope);
m_ScriptScope.ReleaseFunction(hScriptPrecache);
}
}
void CBaseEntity::RunOnPostSpawnScripts(void)
{
if (m_iszVScripts == NULL_STRING)
{
return;
}
HSCRIPT hFuncConnect = g_pScriptVM->LookupFunction("ConnectOutputs");
if (hFuncConnect)
{
g_pScriptVM->Call(hFuncConnect, NULL, true, NULL, (HSCRIPT)m_ScriptScope);
g_pScriptVM->ReleaseFunction(hFuncConnect);
}
HSCRIPT hFuncDisp = m_ScriptScope.LookupFunction("DispatchOnPostSpawn");
if (hFuncDisp)
{
variant_t variant;
variant.SetString(MAKE_STRING("DispatchOnPostSpawn"));
g_EventQueue.AddEvent(this, "CallScriptFunction", variant, 0, this, this);
m_ScriptScope.ReleaseFunction(hFuncDisp);
}
}
HSCRIPT CBaseEntity::GetScriptOwnerEntity()
{
return ToHScript(GetOwnerEntity());
}
void CBaseEntity::SetScriptOwnerEntity(HSCRIPT pOwner)
{
SetOwnerEntity(ToEnt(pOwner));
}
//-----------------------------------------------------------------------------
// VScript access to model's key values
// for iteration and value access, use:
// ScriptFindKey, ScriptGetFirstSubKey, ScriptGetString,
// ScriptGetInt, ScriptGetFloat, ScriptGetNextKey
//-----------------------------------------------------------------------------
HSCRIPT CBaseEntity::ScriptGetModelKeyValues( void )
{
KeyValues *pModelKeyValues = new KeyValues("");
HSCRIPT hScript = NULL;
const char *pszModelName = modelinfo->GetModelName( GetModel() );
const char *pBuffer = modelinfo->GetModelKeyValueText( GetModel() ) ;
if ( pModelKeyValues->LoadFromBuffer( pszModelName, pBuffer ) )
{
// UNDONE: how does destructor get called on this
m_pScriptModelKeyValues = new CScriptKeyValues( pModelKeyValues );
// UNDONE: who calls ReleaseInstance on this??? Does name need to be unique???
hScript = g_pScriptVM->RegisterInstance( m_pScriptModelKeyValues );
/*
KeyValues *pParticleEffects = pModelKeyValues->FindKey("Particles");
if ( pParticleEffects )
{
// Start grabbing the sounds and slotting them in
for ( KeyValues *pSingleEffect = pParticleEffects->GetFirstSubKey(); pSingleEffect; pSingleEffect = pSingleEffect->GetNextKey() )
{
const char *pParticleEffectName = pSingleEffect->GetString( "name", "" );
PrecacheParticleSystem( pParticleEffectName );
}
}
*/
}
return hScript;
}
void CBaseEntity::ScriptSetLocalAngularVelocity(float pitchVel, float yawVel, float rollVel)
{
QAngle qa;
qa.Init(pitchVel, yawVel, rollVel);
SetLocalAngularVelocity(qa);
}
const Vector& CBaseEntity::ScriptGetLocalAngularVelocity(void)
{
QAngle qa = GetLocalAngularVelocity();
static Vector v;
v.x = qa.x;
v.y = qa.y;
v.z = qa.z;
return v;
}
//-----------------------------------------------------------------------------
// Vscript: Gets the min collision bounds, centered on object
//-----------------------------------------------------------------------------
const Vector& CBaseEntity::ScriptGetBoundingMins(void)
{
return m_Collision.OBBMins();
}
//-----------------------------------------------------------------------------
// Vscript: Gets the max collision bounds, centered on object
//-----------------------------------------------------------------------------
const Vector& CBaseEntity::ScriptGetBoundingMaxs(void)
{
return m_Collision.OBBMaxs();
}
#ifdef MAPBASE
extern int EntityFactory_AutoComplete( const char *cmdname, CUtlVector< CUtlString > &commands, CUtlRBTree< CUtlString > &symbols, char *substring, int checklen = 0 );

View File

@ -21,6 +21,9 @@
#include "shareddefs.h"
#include "engine/ivmodelinfo.h"
#include "vscript/ivscript.h"
#include "vscript_server.h"
class CDamageModifier;
class CDmgAccumulator;
@ -311,11 +314,13 @@ a list of all CBaseEntitys is kept in gEntList
CBaseEntity *CreateEntityByName( const char *className, int iForceEdictIndex = -1 );
CBaseNetworkable *CreateNetworkableByName( const char *className );
CBaseEntity* ToEnt(HSCRIPT hScript);
// creates an entity and calls all the necessary spawn functions
extern void SpawnEntityByName( const char *className, CEntityMapData *mapData = NULL );
// calls the spawn functions for an entity
extern int DispatchSpawn( CBaseEntity *pEntity );
extern int DispatchSpawn( CBaseEntity *pEntity, bool bRunVScripts = true);
inline CBaseEntity *GetContainingEntity( edict_t *pent );
@ -379,6 +384,8 @@ public:
DECLARE_SERVERCLASS();
// data description
DECLARE_DATADESC();
// script description
DECLARE_ENT_SCRIPTDESC();
// memory handling
void *operator new( size_t stAllocateBlock );
@ -493,6 +500,8 @@ public:
virtual void SetOwnerEntity( CBaseEntity* pOwner );
void SetEffectEntity( CBaseEntity *pEffectEnt );
CBaseEntity *GetEffectEntity() const;
HSCRIPT GetScriptOwnerEntity();
virtual void SetScriptOwnerEntity(HSCRIPT pOwner);
// Only CBaseEntity implements these. CheckTransmit calls the virtual ShouldTransmit to see if the
// entity wants to be sent. If so, it calls SetTransmit, which will mark any dependents for transmission too.
@ -563,9 +572,14 @@ public:
virtual bool KeyValue( const char *szKeyName, float flValue );
virtual bool KeyValue( const char *szKeyName, const Vector &vecValue );
virtual bool GetKeyValue( const char *szKeyName, char *szValue, int iMaxLen );
bool KeyValueFromString( const char *szKeyName, const char *szValue ) { return KeyValue( szKeyName, szValue ); }
bool KeyValueFromFloat( const char *szKeyName, float flValue ) { return KeyValue( szKeyName, flValue ); }
bool KeyValueFromInt( const char *szKeyName, int nValue ) { return KeyValue( szKeyName, nValue ); }
bool KeyValueFromVector( const char *szKeyName, const Vector &vecValue ) { return KeyValue( szKeyName, vecValue ); }
void ValidateEntityConnections();
void FireNamedOutput( const char *pszOutput, variant_t variant, CBaseEntity *pActivator, CBaseEntity *pCaller, float flDelay = 0.0f );
CBaseEntityOutput *FindNamedOutput( const char *pszOutput );
// Activate - called for each entity after each load game and level load
virtual void Activate( void );
@ -588,6 +602,8 @@ public:
int GetParentAttachment();
string_t GetEntityName();
const char* GetEntityNameAsCStr(); // This method is temporary for VSCRIPT functionality until we figure out what to do with string_t (sjb)
const char* GetPreTemplateName(); // Not threadsafe. Get the name stripped of template unique decoration
bool NameMatches( const char *pszNameOrWildcard );
bool ClassMatches( const char *pszClassOrWildcard );
@ -735,6 +751,14 @@ public:
COutputEvent m_OnKilled;
#endif
void InputRunScript(inputdata_t& inputdata);
void InputRunScriptFile(inputdata_t& inputdata);
void InputCallScriptFunction(inputdata_t& inputdata);
bool RunScriptFile(const char* pScriptFile, bool bUseRootScope = false);
bool RunScript(const char* pScriptText, const char* pDebugFilename = "CBaseEntity::RunScript");
// Returns the origin at which to play an inputted dispatcheffect
virtual void GetInputDispatchEffectPosition( const char *sInputString, Vector &pOrigin, QAngle &pAngles );
@ -1715,7 +1739,7 @@ private:
// was pev->flags
CNetworkVarForDerived( int, m_fFlags );
string_t m_iName; // name used to identify this entity
CNetworkVar( string_t, m_iName ); // name used to identify this entity
// Damage modifiers
friend class CDamageModifier;
@ -1920,6 +1944,59 @@ public:
{
return s_bAbsQueriesValid;
}
// VSCRIPT
HSCRIPT GetScriptInstance();
bool ValidateScriptScope();
virtual void RunVScripts();
bool CallScriptFunction(const char* pFunctionName, ScriptVariant_t* pFunctionReturn);
void ConnectOutputToScript(const char* pszOutput, const char* pszScriptFunc);
void DisconnectOutputFromScript(const char* pszOutput, const char* pszScriptFunc);
void ScriptThink();
const char* GetScriptId();
HSCRIPT GetScriptScope();
void RunPrecacheScripts(void);
void RunOnPostSpawnScripts(void);
HSCRIPT ScriptGetMoveParent(void);
HSCRIPT ScriptGetRootMoveParent();
HSCRIPT ScriptFirstMoveChild(void);
HSCRIPT ScriptNextMovePeer(void);
const Vector& ScriptEyePosition(void) { static Vector vec; vec = EyePosition(); return vec; }
void ScriptSetAngles(float fPitch, float fYaw, float fRoll) { QAngle angles(fPitch, fYaw, fRoll); Teleport(NULL, &angles, NULL); }
const Vector& ScriptGetAngles(void) { static Vector vec; QAngle qa = GetAbsAngles(); vec.x = qa.x; vec.y = qa.y; vec.z = qa.z; return vec; }
void ScriptSetSize(const Vector& mins, const Vector& maxs) { UTIL_SetSize(this, mins, maxs); }
void ScriptUtilRemove(void) { UTIL_Remove(this); }
void ScriptSetOwner(HSCRIPT hEntity) { SetOwnerEntity(ToEnt(hEntity)); }
void ScriptSetOrigin(const Vector& v) { Teleport(&v, NULL, NULL); }
void ScriptSetForward(const Vector& v) { QAngle angles; VectorAngles(v, angles); Teleport(NULL, &angles, NULL); }
const Vector& ScriptGetForward(void) { static Vector vecForward; GetVectors(&vecForward, NULL, NULL); return vecForward; }
const Vector& ScriptGetLeft(void) { static Vector vecLeft; GetVectors(NULL, &vecLeft, NULL); return vecLeft; }
const Vector& ScriptGetUp(void) { static Vector vecUp; GetVectors(NULL, NULL, &vecUp); return vecUp; }
const char* ScriptGetModelName(void) const;
HSCRIPT ScriptGetModelKeyValues(void);
void ScriptEmitSound(const char* soundname);
float ScriptSoundDuration(const char* soundname, const char* actormodel);
void VScriptPrecacheScriptSound(const char* soundname);
const Vector& ScriptGetLocalAngularVelocity( void );
void ScriptSetLocalAngularVelocity( float pitchVel, float yawVel, float rollVel );
const Vector& ScriptGetBoundingMins(void);
const Vector& ScriptGetBoundingMaxs(void);
string_t m_iszVScripts;
string_t m_iszScriptThinkFunction;
CScriptScope m_ScriptScope;
HSCRIPT m_hScriptInstance;
string_t m_iszScriptId;
CScriptKeyValues* m_pScriptModelKeyValues;
};
// Send tables exposed in this module.
@ -2048,6 +2125,21 @@ inline string_t CBaseEntity::GetEntityName()
return m_iName;
}
inline const char *CBaseEntity::GetEntityNameAsCStr()
{
return STRING(m_iName.Get());
}
inline const char *CBaseEntity::GetPreTemplateName()
{
const char *pszDelimiter = V_strrchr( STRING(m_iName.Get()), '&' );
if ( !pszDelimiter )
return STRING( m_iName.Get() );
static char szStrippedName[128];
V_strncpy( szStrippedName, STRING( m_iName.Get() ), MIN( ARRAYSIZE(szStrippedName), pszDelimiter - STRING( m_iName.Get() ) + 1 ) );
return szStrippedName;
}
inline void CBaseEntity::SetName( string_t newName )
{
m_iName = newName;
@ -2726,6 +2818,14 @@ inline void CBaseEntity::FireBullets( int cShots, const Vector &vecSrc,
FireBullets( info );
}
//-----------------------------------------------------------------------------
// VScript
//-----------------------------------------------------------------------------
inline const char* CBaseEntity::ScriptGetModelName(void) const
{
return STRING(m_ModelName);
}
// Ugly technique to override base member functions
// Normally it's illegal to cast a pointer to a member function of a derived class to a pointer to a
// member function of a base class. static_cast is a sleezy way around that problem.

View File

@ -95,6 +95,10 @@ BEGIN_DATADESC( CBaseFlex )
END_DATADESC()
BEGIN_ENT_SCRIPTDESC( CBaseFlex, CBaseAnimating, "Animated characters who have vertex flex capability." )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetOldestScene, "GetCurrentScene", "Returns the instance of the oldest active scene entity (if any)." )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetSceneByIndex, "GetSceneByIndex", "Returns the instance of the scene entity at the specified index." )
END_SCRIPTDESC();
LINK_ENTITY_TO_CLASS( funCBaseFlex, CBaseFlex ); // meaningless independant class!!
@ -421,7 +425,8 @@ void CBaseFlex::AddSceneEvent( CChoreoScene *scene, CChoreoEvent *event, CBaseEn
info.m_pEvent = event;
info.m_pScene = scene;
info.m_hTarget = pTarget;
info.m_bStarted = false;
info.m_bStarted = false;
info.m_hSceneEntity = pSceneEnt;
#ifdef MAPBASE
if (StartSceneEvent( &info, scene, event, actor, pTarget, pSceneEnt ))
@ -2029,6 +2034,37 @@ float CBaseFlex::PlayAutoGeneratedSoundScene( const char *soundname )
#endif
//--------------------------------------------------------------------------------------------------
// Returns the script instance of the scene entity associated with our oldest ("top level") scene event
//--------------------------------------------------------------------------------------------------
HSCRIPT CBaseFlex::ScriptGetOldestScene( void )
{
if ( m_SceneEvents.Count() > 0 )
{
CSceneEventInfo curScene = m_SceneEvents.Head();
return ToHScript( (CBaseEntity*)(curScene.m_hSceneEntity.Get()) );
}
else
{
return NULL;
}
}
//--------------------------------------------------------------------------------------------------
// Returns the script instance of the scene at the specified index, or null if index >= count
//--------------------------------------------------------------------------------------------------
HSCRIPT CBaseFlex::ScriptGetSceneByIndex( int index )
{
if ( m_SceneEvents.IsValidIndex( index ) )
{
CSceneEventInfo curScene = m_SceneEvents.Element( index );
return ToHScript( (CBaseEntity*)(curScene.m_hSceneEntity.Get()) );
}
else
{
return NULL;
}
}
// FIXME: move to CBaseActor

View File

@ -46,6 +46,8 @@ public:
DECLARE_SERVERCLASS();
DECLARE_DATADESC();
DECLARE_PREDICTABLE();
// script description
DECLARE_ENT_SCRIPTDESC();
// Construction
CBaseFlex( void );
@ -130,6 +132,10 @@ public:
virtual float PlayAutoGeneratedSoundScene( const char *soundname );
#endif
// Returns the script instance of the scene entity associated with our oldest ("top level") scene event
virtual HSCRIPT ScriptGetOldestScene( void );
virtual HSCRIPT ScriptGetSceneByIndex( int index );
virtual int GetSpecialDSP( void ) { return 0; }
protected:

View File

@ -396,6 +396,28 @@ void CBaseEntityOutput::AddEventAction( CEventAction *pEventAction )
m_ActionList = pEventAction;
}
void CBaseEntityOutput::RemoveEventAction( CEventAction *pEventAction )
{
CEventAction *pAction = GetActionList();
CEventAction *pPrevAction = NULL;
while ( pAction )
{
if ( pAction == pEventAction )
{
if ( !pPrevAction )
{
m_ActionList = NULL;
}
else
{
pPrevAction->m_pNext = pAction->m_pNext;
}
return;
}
pAction = pAction->m_pNext;
}
}
// save data description for the event queue
BEGIN_SIMPLE_DATADESC( CBaseEntityOutput )

View File

@ -26,6 +26,7 @@ class IDataCache;
class IMDLCache;
class IServerEngineTools;
class IXboxSystem;
class IScriptManager;
class CSteamAPIContext;
class CSteamGameServerAPIContext;
@ -43,6 +44,7 @@ extern IDataCache *datacache;
extern IMDLCache *mdlcache;
extern IServerEngineTools *serverenginetools;
extern IXboxSystem *xboxsystem; // 360 only
extern IScriptManager *scriptmanager;
extern CSteamAPIContext *steamapicontext; // available on game clients
extern CSteamGameServerAPIContext *steamgameserverapicontext; //available on game servers

View File

@ -667,7 +667,7 @@ CBaseEntity *CGlobalEntityList::FindEntityByName( CBaseEntity *pStartEntity, con
continue;
}
if ( !ent->m_iName )
if ( !ent->m_iName.Get() )
continue;
if ( ent->NameMatches( szName ) )

View File

@ -63,6 +63,7 @@ public:
void ParseEventAction( const char *EventData );
void AddEventAction( CEventAction *pEventAction );
void RemoveEventAction( CEventAction *pEventAction );
int Save( ISave &save );
int Restore( IRestore &restore, int elementCount );

View File

@ -30,6 +30,7 @@ class CEnvEntityMaker : public CPointEntity
DECLARE_CLASS( CEnvEntityMaker, CPointEntity );
public:
DECLARE_DATADESC();
DECLARE_ENT_SCRIPTDESC();
virtual void Spawn( void );
virtual void Activate( void );
@ -43,6 +44,10 @@ public:
void InputForceSpawnAtPosition( inputdata_t &inputdata );
#endif
void SpawnEntityFromScript();
void SpawnEntityAtEntityOriginFromScript(HSCRIPT hEntity);
void SpawnEntityAtNamedEntityOriginFromScript(const char* pszName);
void SpawnEntityAtLocationFromScript(const Vector& vecAlternateOrigin, const Vector& vecAlternateAngles);
private:
CPointTemplate *FindTemplate();
@ -102,6 +107,13 @@ BEGIN_DATADESC( CEnvEntityMaker )
DEFINE_THINKFUNC( CheckSpawnThink ),
END_DATADESC()
BEGIN_ENT_SCRIPTDESC( CEnvEntityMaker, CBaseEntity, "env_entity_maker" )
DEFINE_SCRIPTFUNC_NAMED( SpawnEntityFromScript, "SpawnEntity", "Create an entity at the location of the maker" )
DEFINE_SCRIPTFUNC_NAMED( SpawnEntityAtEntityOriginFromScript, "SpawnEntityAtEntityOrigin", "Create an entity at the location of a specified entity instance" )
DEFINE_SCRIPTFUNC_NAMED( SpawnEntityAtNamedEntityOriginFromScript, "SpawnEntityAtNamedEntityOrigin", "Create an entity at the location of a named entity" )
DEFINE_SCRIPTFUNC_NAMED( SpawnEntityAtLocationFromScript, "SpawnEntityAtLocation", "Create an entity at a specified location and orientaton, orientation is Euler angle in degrees (pitch, yaw, roll)" )
END_SCRIPTDESC()
LINK_ENTITY_TO_CLASS( env_entity_maker, CEnvEntityMaker );
@ -266,8 +278,50 @@ void CEnvEntityMaker::SpawnEntity( Vector vecAlternateOrigin, QAngle vecAlternat
}
}
#endif
pTemplate->CreationComplete( hNewEntities );
}
//-----------------------------------------------------------------------------
// Purpose: Spawn an instance of the entity
//-----------------------------------------------------------------------------
void CEnvEntityMaker::SpawnEntityFromScript()
{
SpawnEntity();
}
//-----------------------------------------------------------------------------
// Purpose: Spawn an instance of the entity
//-----------------------------------------------------------------------------
void CEnvEntityMaker::SpawnEntityAtEntityOriginFromScript( HSCRIPT hEntity )
{
CBaseEntity *pTargetEntity = ToEnt( hEntity );
if ( pTargetEntity )
{
SpawnEntity( pTargetEntity->GetAbsOrigin(), pTargetEntity->GetAbsAngles() );
}
}
//-----------------------------------------------------------------------------
// Purpose: Spawn an instance of the entity
//-----------------------------------------------------------------------------
void CEnvEntityMaker::SpawnEntityAtNamedEntityOriginFromScript( const char *pszName )
{
CBaseEntity *pTargetEntity = gEntList.FindEntityByName( NULL, pszName, this, NULL, NULL );
if( pTargetEntity )
{
SpawnEntity( pTargetEntity->GetAbsOrigin(), pTargetEntity->GetAbsAngles() );
}
}
//-----------------------------------------------------------------------------
// Purpose: Spawn an instance of the entity
//-----------------------------------------------------------------------------
void CEnvEntityMaker::SpawnEntityAtLocationFromScript( const Vector &vecAlternateOrigin, const Vector &vecAlternateAngles )
{
SpawnEntity( vecAlternateOrigin, *((QAngle *)&vecAlternateAngles) );
}
//-----------------------------------------------------------------------------
// Purpose: Returns whether or not the template entities can fit if spawned.

View File

@ -93,6 +93,9 @@
#include "world.h"
#endif
#include "vscript/ivscript.h"
#include "vscript_server.h"
#ifdef TF_DLL
#include "gc_clientsystem.h"
@ -185,6 +188,7 @@ IServerEngineTools *serverenginetools = NULL;
ISceneFileCache *scenefilecache = NULL;
IXboxSystem *xboxsystem = NULL; // Xbox 360 only
IMatchmaking *matchmaking = NULL; // Xbox 360 only
IScriptManager *scriptmanager = NULL;
#if defined( REPLAY_ENABLED )
IReplaySystem *g_pReplay = NULL;
IServerReplayContext *g_pReplayServerContext = NULL;
@ -627,6 +631,11 @@ bool CServerGameDLL::DLLInit( CreateInterfaceFn appSystemFactory,
if ( IsX360() && (matchmaking = (IMatchmaking *)appSystemFactory( VENGINE_MATCHMAKING_VERSION, NULL )) == NULL )
return false;
if (!CommandLine()->CheckParm("-noscripting"))
{
scriptmanager = (IScriptManager*)appSystemFactory(VSCRIPT_INTERFACE_VERSION, NULL);
}
// If not running dedicated, grab the engine vgui interface
if ( !engine->IsDedicatedServer() )
{
@ -684,6 +693,7 @@ bool CServerGameDLL::DLLInit( CreateInterfaceFn appSystemFactory,
g_pGameSaveRestoreBlockSet->AddBlockHandler( GetCommentarySaveRestoreBlockHandler() );
g_pGameSaveRestoreBlockSet->AddBlockHandler( GetEventQueueSaveRestoreBlockHandler() );
g_pGameSaveRestoreBlockSet->AddBlockHandler( GetAchievementSaveRestoreBlockHandler() );
g_pGameSaveRestoreBlockSet->AddBlockHandler( GetVScriptSaveRestoreBlockHandler() );
// The string system must init first + shutdown last
IGameSystem::Add( GameStringSystem() );
@ -762,6 +772,7 @@ void CServerGameDLL::DLLShutdown( void )
// Due to dependencies, these are not autogamesystems
ModelSoundsCacheShutdown();
g_pGameSaveRestoreBlockSet->RemoveBlockHandler( GetVScriptSaveRestoreBlockHandler() );
g_pGameSaveRestoreBlockSet->RemoveBlockHandler( GetAchievementSaveRestoreBlockHandler() );
g_pGameSaveRestoreBlockSet->RemoveBlockHandler( GetCommentarySaveRestoreBlockHandler() );
g_pGameSaveRestoreBlockSet->RemoveBlockHandler( GetEventQueueSaveRestoreBlockHandler() );

View File

@ -27,6 +27,126 @@
extern CServerGameDLL g_ServerGameDLL;
//-----------------------------------------------------------------------------
// Purpose: An entity that acts as a container for game scripts.
//-----------------------------------------------------------------------------
#define MAX_SCRIPT_GROUP 16
class CLogicScript : public CPointEntity
{
public:
DECLARE_CLASS( CLogicScript, CPointEntity );
DECLARE_DATADESC();
void RunVScripts()
{
/*
EntityGroup <- [];
function __AppendToScriptGroup( name )
{
if ( name.len() == 0 )
{
EntityGroup.append( null );
}
else
{
local ent = Entities.FindByName( null, name );
EntityGroup.append( ent );
if ( ent != null )
{
ent.ValidateScriptScope();
ent.GetScriptScope().EntityGroup <- EntityGroup;
}
}
}
*/
static const char szAddCode[] =
{
0x45,0x6e,0x74,0x69,0x74,0x79,0x47,0x72,0x6f,0x75,0x70,0x20,0x3c,0x2d,0x20,0x5b,0x5d,0x3b,0x0d,0x0a,
0x66,0x75,0x6e,0x63,0x74,0x69,0x6f,0x6e,0x20,0x5f,0x5f,0x41,0x70,0x70,0x65,0x6e,0x64,0x54,0x6f,0x53,
0x63,0x72,0x69,0x70,0x74,0x47,0x72,0x6f,0x75,0x70,0x28,0x20,0x6e,0x61,0x6d,0x65,0x20,0x29,0x20,0x0d,
0x0a,0x7b,0x0d,0x0a,0x09,0x69,0x66,0x20,0x28,0x20,0x6e,0x61,0x6d,0x65,0x2e,0x6c,0x65,0x6e,0x28,0x29,
0x20,0x3d,0x3d,0x20,0x30,0x20,0x29,0x20,0x0d,0x0a,0x09,0x7b,0x20,0x0d,0x0a,0x09,0x09,0x45,0x6e,0x74,
0x69,0x74,0x79,0x47,0x72,0x6f,0x75,0x70,0x2e,0x61,0x70,0x70,0x65,0x6e,0x64,0x28,0x20,0x6e,0x75,0x6c,
0x6c,0x20,0x29,0x3b,0x20,0x0d,0x0a,0x09,0x7d,0x20,0x0d,0x0a,0x09,0x65,0x6c,0x73,0x65,0x0d,0x0a,0x09,
0x7b,0x20,0x0d,0x0a,0x09,0x09,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x65,0x6e,0x74,0x20,0x3d,0x20,0x45,0x6e,
0x74,0x69,0x74,0x69,0x65,0x73,0x2e,0x46,0x69,0x6e,0x64,0x42,0x79,0x4e,0x61,0x6d,0x65,0x28,0x20,0x6e,
0x75,0x6c,0x6c,0x2c,0x20,0x6e,0x61,0x6d,0x65,0x20,0x29,0x3b,0x0d,0x0a,0x09,0x09,0x45,0x6e,0x74,0x69,
0x74,0x79,0x47,0x72,0x6f,0x75,0x70,0x2e,0x61,0x70,0x70,0x65,0x6e,0x64,0x28,0x20,0x65,0x6e,0x74,0x20,
0x29,0x3b,0x0d,0x0a,0x09,0x09,0x69,0x66,0x20,0x28,0x20,0x65,0x6e,0x74,0x20,0x21,0x3d,0x20,0x6e,0x75,
0x6c,0x6c,0x20,0x29,0x0d,0x0a,0x09,0x09,0x7b,0x0d,0x0a,0x09,0x09,0x09,0x65,0x6e,0x74,0x2e,0x56,0x61,
0x6c,0x69,0x64,0x61,0x74,0x65,0x53,0x63,0x72,0x69,0x70,0x74,0x53,0x63,0x6f,0x70,0x65,0x28,0x29,0x3b,
0x0d,0x0a,0x09,0x09,0x09,0x65,0x6e,0x74,0x2e,0x47,0x65,0x74,0x53,0x63,0x72,0x69,0x70,0x74,0x53,0x63,
0x6f,0x70,0x65,0x28,0x29,0x2e,0x45,0x6e,0x74,0x69,0x74,0x79,0x47,0x72,0x6f,0x75,0x70,0x20,0x3c,0x2d,
0x20,0x45,0x6e,0x74,0x69,0x74,0x79,0x47,0x72,0x6f,0x75,0x70,0x3b,0x0d,0x0a,0x09,0x09,0x7d,0x0d,0x0a,
0x09,0x7d,0x0d,0x0a,0x7d,0x0d,0x0a,0x00
};
int iLastMember;
for ( iLastMember = MAX_SCRIPT_GROUP - 1; iLastMember >= 0; iLastMember-- )
{
if ( m_iszGroupMembers[iLastMember] != NULL_STRING )
{
break;
}
}
if ( iLastMember >= 0 )
{
HSCRIPT hAddScript = g_pScriptVM->CompileScript( szAddCode );
if ( hAddScript )
{
ValidateScriptScope();
m_ScriptScope.Run( hAddScript );
HSCRIPT hAddFunc = m_ScriptScope.LookupFunction( "__AppendToScriptGroup" );
if ( hAddFunc )
{
for ( int i = 0; i <= iLastMember; i++ )
{
m_ScriptScope.Call( hAddFunc, NULL, STRING(m_iszGroupMembers[i]) );
}
g_pScriptVM->ReleaseFunction( hAddFunc );
m_ScriptScope.ClearValue( "__AppendToScriptGroup" );
}
g_pScriptVM->ReleaseScript( hAddScript );
}
}
BaseClass::RunVScripts();
}
string_t m_iszGroupMembers[MAX_SCRIPT_GROUP];
};
LINK_ENTITY_TO_CLASS( logic_script, CLogicScript );
BEGIN_DATADESC( CLogicScript )
// Silence, Classcheck!
// DEFINE_ARRAY( m_iszGroupMembers, FIELD_STRING, MAX_NUM_TEMPLATES ),
DEFINE_KEYFIELD( m_iszGroupMembers[0], FIELD_STRING, "Group00"),
DEFINE_KEYFIELD( m_iszGroupMembers[1], FIELD_STRING, "Group01"),
DEFINE_KEYFIELD( m_iszGroupMembers[2], FIELD_STRING, "Group02"),
DEFINE_KEYFIELD( m_iszGroupMembers[3], FIELD_STRING, "Group03"),
DEFINE_KEYFIELD( m_iszGroupMembers[4], FIELD_STRING, "Group04"),
DEFINE_KEYFIELD( m_iszGroupMembers[5], FIELD_STRING, "Group05"),
DEFINE_KEYFIELD( m_iszGroupMembers[6], FIELD_STRING, "Group06"),
DEFINE_KEYFIELD( m_iszGroupMembers[7], FIELD_STRING, "Group07"),
DEFINE_KEYFIELD( m_iszGroupMembers[8], FIELD_STRING, "Group08"),
DEFINE_KEYFIELD( m_iszGroupMembers[9], FIELD_STRING, "Group09"),
DEFINE_KEYFIELD( m_iszGroupMembers[10], FIELD_STRING, "Group10"),
DEFINE_KEYFIELD( m_iszGroupMembers[11], FIELD_STRING, "Group11"),
DEFINE_KEYFIELD( m_iszGroupMembers[12], FIELD_STRING, "Group12"),
DEFINE_KEYFIELD( m_iszGroupMembers[13], FIELD_STRING, "Group13"),
DEFINE_KEYFIELD( m_iszGroupMembers[14], FIELD_STRING, "Group14"),
DEFINE_KEYFIELD( m_iszGroupMembers[15], FIELD_STRING, "Group16"),
END_DATADESC()
//-----------------------------------------------------------------------------
// Purpose: Compares a set of integer inputs to the one main input

View File

@ -18,6 +18,8 @@
#include "IEffects.h"
#include "props.h"
#include "point_template.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
@ -114,6 +116,8 @@ END_DATADESC()
//-----------------------------------------------------------------------------
void CBaseNPCMaker::Spawn( void )
{
ScriptInstallPreSpawnHook();
SetSolid( SOLID_NONE );
m_nLiveChildren = 0;
Precache();
@ -830,6 +834,12 @@ void CTemplateNPCMaker::MakeNPC( void )
pent->SetAbsAngles( angles );
}
if ( !ScriptPreInstanceSpawn( &m_ScriptScope, pEntity, m_iszTemplateData ) )
{
UTIL_RemoveImmediate( pEntity );
return;
}
m_OnSpawnNPC.Set( pEntity, pEntity, this );
if ( m_spawnflags & SF_NPCMAKER_FADE )
@ -867,6 +877,8 @@ void CTemplateNPCMaker::MakeNPC( void )
SetUse( NULL );
}
}
ScriptPostSpawn( &m_ScriptScope, &pEntity, 1 );
}
//-----------------------------------------------------------------------------

View File

@ -478,6 +478,10 @@ BEGIN_DATADESC( CBasePlayer )
// DEFINE_UTLVECTOR( m_vecPlayerSimInfo ),
END_DATADESC()
BEGIN_ENT_SCRIPTDESC( CBasePlayer, CBaseAnimating, "The player entity." )
DEFINE_SCRIPTFUNC_NAMED( ScriptIsPlayerNoclipping, "IsNoclipping", "Returns true if the player is in noclip mode." )
END_SCRIPTDESC();
int giPrecacheGrunt = 0;
edict_t *CBasePlayer::s_PlayerEdict = NULL;
@ -690,6 +694,11 @@ CBasePlayer::~CBasePlayer( )
//-----------------------------------------------------------------------------
void CBasePlayer::UpdateOnRemove( void )
{
if ( !g_pGameRules->IsMultiplayer() && g_pScriptVM )
{
g_pScriptVM->SetValue( "player", SCRIPT_VARIANT_NULL );
}
VPhysicsDestroyObject();
// Remove him from his current team
@ -5110,6 +5119,11 @@ void CBasePlayer::Spawn( void )
UpdateLastKnownArea();
m_weaponFiredTimer.Invalidate();
if ( !g_pGameRules->IsMultiplayer() && g_pScriptVM )
{
g_pScriptVM->SetValue( "player", GetScriptInstance() );
}
}
void CBasePlayer::Activate( void )
@ -5300,6 +5314,14 @@ void CBasePlayer::OnRestore( void )
m_nVehicleViewSavedFrame = 0;
m_nBodyPitchPoseParam = LookupPoseParameter( "body_pitch" );
// HACK: (03/25/09) Then the player goes across a transition it doesn't spawn and register
// it's instance. We're hacking around this for now, but this will go away when we get around to
// having entities cross transitions and keep their script state.
if ( !g_pGameRules->IsMultiplayer() && g_pScriptVM && (gpGlobals->eLoadType == MapLoad_Transition) )
{
g_pScriptVM->SetValue( "player", GetScriptInstance() );
}
}
/* void CBasePlayer::SetTeamName( const char *pTeamName )
@ -6864,6 +6886,14 @@ void CBasePlayer::ShowCrosshair( bool bShow )
}
}
//-----------------------------------------------------------------------------
// Used by vscript to determine if the player is noclipping
//-----------------------------------------------------------------------------
bool CBasePlayer::ScriptIsPlayerNoclipping(void)
{
return (GetMoveType() == MOVETYPE_NOCLIP);
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------

View File

@ -244,6 +244,8 @@ protected:
public:
DECLARE_DATADESC();
DECLARE_SERVERCLASS();
// script description
DECLARE_ENT_SCRIPTDESC();
CBasePlayer();
~CBasePlayer();
@ -386,6 +388,8 @@ public:
void ShowViewModel( bool bShow );
void ShowCrosshair( bool bShow );
bool ScriptIsPlayerNoclipping(void);
// View model prediction setup
void CalcView( Vector &eyeOrigin, QAngle &eyeAngles, float &zNear, float &zFar, float &fov );

View File

@ -53,24 +53,6 @@ END_DATADESC()
LINK_ENTITY_TO_CLASS( point_devshot_camera, CPointDevShotCamera );
//-----------------------------------------------------------------------------
// Purpose: Convenience function so we don't have to make this check all over
//-----------------------------------------------------------------------------
static CBasePlayer * UTIL_GetLocalPlayerOrListenServerHost( void )
{
if ( gpGlobals->maxClients > 1 )
{
if ( engine->IsDedicatedServer() )
{
return NULL;
}
return UTIL_GetListenServerHost();
}
return UTIL_GetLocalPlayer();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------

View File

@ -133,6 +133,8 @@ void PrecachePointTemplates()
void CPointTemplate::Spawn( void )
{
Precache();
ScriptInstallPreSpawnHook();
ValidateScriptScope();
}
void CPointTemplate::Precache()
@ -381,7 +383,15 @@ bool CPointTemplate::CreateInstance( const Vector &vecOrigin, const QAngle &vecA
pEntity->SetAbsOrigin( vecNewOrigin );
pEntity->SetAbsAngles( vecNewAngles );
pSpawnList[i].m_pEntity = pEntity;
if (ScriptPreInstanceSpawn(&m_ScriptScope, pEntity, Templates_FindByIndex(iTemplateIndex)))
{
pSpawnList[i].m_pEntity = pEntity;
}
else
{
pSpawnList[i].m_pEntity = NULL;
UTIL_RemoveImmediate(pEntity);
}
pSpawnList[i].m_nDepth = 0;
pSpawnList[i].m_pDeferredParent = NULL;
}
@ -474,6 +484,17 @@ bool CPointTemplate::CreateSpecificInstance( int iTemplate, const Vector &vecOri
}
#endif
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CPointTemplate::CreationComplete( const CUtlVector<CBaseEntity*> &entities )
{
if ( !entities.Count() )
return;
ScriptPostSpawn( &m_ScriptScope, (CBaseEntity **)entities.Base(), entities.Count() );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : &inputdata -
@ -514,3 +535,72 @@ void CPointTemplate::InputForceSpawnRandomTemplate( inputdata_t &inputdata )
m_pOutputOutEntity.Set(pEntity, pEntity, this);
}
#endif
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void ScriptInstallPreSpawnHook()
{
#ifdef IS_WINDOWS_PC
if ( !g_pScriptVM->ValueExists( "__ExecutePreSpawn " ) )
{
//g_pScriptVM->Run( g_Script_spawn_helper );
}
#endif
}
//-----------------------------------------------------------------------------
// Purpose: This function is called after a spawner creates its child entity
// but before the keyvalues are injected. This gives us an
// opportunity to change any keyvalues before the entity is
// configured and spawned. In this case, we see if there is a VScript
// that wants to change anything about this entity.
//-----------------------------------------------------------------------------
bool ScriptPreInstanceSpawn( CScriptScope *pScriptScope, CBaseEntity *pChild, string_t iszKeyValueData )
{
if ( !pScriptScope->IsInitialized() )
return true;
ScriptVariant_t result;
if ( pScriptScope->Call( "__ExecutePreSpawn", &result, ToHScript( pChild ) ) != SCRIPT_DONE )
return true;
if ( ( result.m_type == FIELD_BOOLEAN && !result.m_bool ) || ( result.m_type == FIELD_INTEGER && !result.m_int ) )
return false;
return true;
}
void ScriptPostSpawn( CScriptScope *pScriptScope, CBaseEntity **ppEntities, int nEntities )
{
if ( !pScriptScope->IsInitialized() )
return;
HSCRIPT hPostSpawnFunc = pScriptScope->LookupFunction( "PostSpawn" );
if ( !hPostSpawnFunc )
return;
ScriptVariant_t varEntityMakerResultTable;
if ( !g_pScriptVM->GetValue( *pScriptScope, "__EntityMakerResult", &varEntityMakerResultTable ) )
return;
if ( varEntityMakerResultTable.m_type != FIELD_HSCRIPT )
return;
HSCRIPT hEntityMakerResultTable = varEntityMakerResultTable.m_hScript;
char szEntName[256];
for ( int i = 0; i < nEntities; i++ )
{
V_strncpy( szEntName, ppEntities[i]->GetEntityNameAsCStr(), ARRAYSIZE(szEntName) );
char *pAmpersand = V_strrchr( szEntName, '&' );
if ( pAmpersand )
*pAmpersand = 0;
g_pScriptVM->SetValue( hEntityMakerResultTable, szEntName, ToHScript( ppEntities[i] ) );
}
pScriptScope->Call( hPostSpawnFunc, NULL, hEntityMakerResultTable );
pScriptScope->Call( "__FinishSpawn" );
g_pScriptVM->ReleaseValue( varEntityMakerResultTable );
g_pScriptVM->ReleaseFunction( hPostSpawnFunc );
}

View File

@ -20,6 +20,10 @@ struct template_t
DECLARE_SIMPLE_DATADESC();
};
void ScriptInstallPreSpawnHook();
bool ScriptPreInstanceSpawn( CScriptScope *pScriptScope, CBaseEntity *pChild, string_t iszKeyValueData );
void ScriptPostSpawn( CScriptScope *pScriptScope, CBaseEntity **ppEntities, int nEntities );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
@ -52,6 +56,7 @@ public:
#ifdef MAPBASE
bool CreateSpecificInstance( int iTemplate, const Vector &vecOrigin, const QAngle &vecAngles, CBaseEntity **pOutEntity );
#endif
void CreationComplete(const CUtlVector<CBaseEntity*>& entities);
// Inputs
void InputForceSpawn( inputdata_t &inputdata );

View File

@ -33,6 +33,8 @@
#include "SceneCache.h"
#include "scripted.h"
#include "env_debughistory.h"
#include "team.h"
#include "triggers.h"
#ifdef HL2_EPISODIC
#include "npc_alyx_episodic.h"
@ -323,6 +325,8 @@ public:
DECLARE_CLASS( CSceneEntity, CPointEntity );
DECLARE_SERVERCLASS();
// script description
DECLARE_ENT_SCRIPTDESC();
CSceneEntity( void );
~CSceneEntity( void );
@ -470,6 +474,8 @@ public:
void InputScriptPlayerDeath( inputdata_t &inputdata );
void AddBroadcastTeamTarget( int nTeamIndex );
void RemoveBroadcastTeamTarget( int nTeamIndex );
// Data
public:
string_t m_iszSceneFile;
@ -543,6 +549,9 @@ public:
virtual CBaseEntity *FindNamedEntity( const char *name, CBaseEntity *pActor = NULL, bool bBaseFlexOnly = false, bool bUseClear = false );
CBaseEntity *FindNamedTarget( string_t iszTarget, bool bBaseFlexOnly = false );
virtual CBaseEntity *FindNamedEntityClosest( const char *name, CBaseEntity *pActor = NULL, bool bBaseFlexOnly = false, bool bUseClear = false, const char *pszSecondary = NULL );
HSCRIPT ScriptFindNamedEntity( const char *name );
bool ScriptLoadSceneFromString( const char * pszFilename, const char *pszData );
private:
@ -764,6 +773,17 @@ BEGIN_DATADESC( CSceneEntity )
DEFINE_OUTPUT( m_OnTrigger16, "OnTrigger16"),
END_DATADESC()
BEGIN_ENT_SCRIPTDESC( CSceneEntity, CBaseEntity, "Choreographed scene which controls animation and/or dialog on one or more actors." )
DEFINE_SCRIPTFUNC( EstimateLength, "Returns length of this scene in seconds." )
DEFINE_SCRIPTFUNC( IsPlayingBack, "If this scene is currently playing." )
DEFINE_SCRIPTFUNC( IsPaused, "If this scene is currently paused." )
DEFINE_SCRIPTFUNC( AddBroadcastTeamTarget, "Adds a team (by index) to the broadcast list" )
DEFINE_SCRIPTFUNC( RemoveBroadcastTeamTarget, "Removes a team (by index) from the broadcast list" )
DEFINE_SCRIPTFUNC_NAMED( ScriptFindNamedEntity, "FindNamedEntity", "given an entity reference, such as !target, get actual entity from scene object" )
DEFINE_SCRIPTFUNC_NAMED( ScriptLoadSceneFromString, "LoadSceneFromString", "given a dummy scene name and a vcd string, load the scene" )
END_SCRIPTDESC();
const ConVar *CSceneEntity::m_pcvSndMixahead = NULL;
//-----------------------------------------------------------------------------
@ -3066,7 +3086,7 @@ void CSceneEntity::StartEvent( float currenttime, CChoreoScene *scene, CChoreoEv
CBaseFlex *pActor = NULL;
CChoreoActor *actor = event->GetActor();
if ( actor )
if ( actor && (event->GetType() != CChoreoEvent::SCRIPT) && (event->GetType() != CChoreoEvent::CAMERA) )
{
pActor = FindNamedActor( actor );
if (pActor == NULL)
@ -3229,6 +3249,80 @@ void CSceneEntity::StartEvent( float currenttime, CChoreoScene *scene, CChoreoEv
}
}
break;
case CChoreoEvent::CAMERA:
{
// begin the camera shot
const char *pszShotType = event->GetParameters();
CBaseEntity *pActor1 = FindNamedEntity( event->GetParameters2( ), pActor );
CBaseEntity *pActor2 = FindNamedEntity( event->GetParameters3( ), pActor );
float duration = event->GetDuration();
// grab any camera we find in the map
// TODO: find camera that is nearest this scene entity?
CTriggerCamera *pCamera = (CTriggerCamera *)gEntList.FindEntityByClassname( NULL, "point_viewcontrol" );
if ( !pCamera )
{
Warning( "CSceneEntity %s unable to find a camera (point_viewcontrol) in this map!\n", STRING(GetEntityName()) );
}
else
{
pCamera->StartCameraShot( pszShotType, this, pActor1, pActor2, duration );
}
}
break;
case CChoreoEvent::SCRIPT:
{
// NOTE: this is only used by auto-generated vcds to embed script commands to map entities.
// vscript call - param1 is entity name, param2 is function name, param3 is function parameter string
// calls a vscript function defined on the scope of the named CBaseEntity object/actor.
// script call is of the format FunctionName(pActor, pThisSceneEntity, pszScriptParameters, duration)
const char *pszActorName = event->GetParameters();
const char *pszFunctionName = event->GetParameters2();
const char *pszScriptParameters = event->GetParameters3();
float duration = event->GetDuration();
// TODO: should be new method CBaseEntity::CallScriptFunctionParams()
CBaseEntity *pEntity = (CBaseEntity *)gEntList.FindEntityByName( NULL, pszActorName );
//START_VMPROFILE
if ( !pEntity )
{
Warning( "CSceneEntity::SCRIPT event - unable to find entity named '%s' in this map!\n", pszActorName );
}
else
{
if( !pEntity->ValidateScriptScope() )
{
DevMsg("\n***\nCChoreoEvent::SCRIPT - FAILED to create private ScriptScope. ABORTING script call\n***\n");
break;
}
HSCRIPT hFunc = pEntity->m_ScriptScope.LookupFunction( pszFunctionName );
if( hFunc )
{
pEntity->m_ScriptScope.Call( hFunc, NULL, ToHScript(this), pszScriptParameters, duration );
pEntity->m_ScriptScope.ReleaseFunction( hFunc );
//UPDATE_VMPROFILE
}
else
{
Warning("CSceneEntity::SCRIPT event - '%s' entity has no script function '%s' defined!\n", pszActorName,pszFunctionName);
}
}
}
break;
case CChoreoEvent::FIRETRIGGER:
{
if ( IsMultiplayer() )
@ -3437,6 +3531,19 @@ void CSceneEntity::EndEvent( float currenttime, CChoreoScene *scene, CChoreoEven
}
}
break;
case CChoreoEvent::CAMERA:
{
// call the end of camera or call a dispatch function
}
break;
case CChoreoEvent::SCRIPT:
{
// call the end of script or call a dispatch function
}
break;
case CChoreoEvent::SEQUENCE:
{
if ( pActor )
@ -4268,6 +4375,53 @@ CBaseEntity *CSceneEntity::FindNamedEntityClosest( const char *name, CBaseEntity
}
HSCRIPT CSceneEntity::ScriptFindNamedEntity(const char* name)
{
return ToHScript(FindNamedEntity(name, NULL, false, false));
}
//-----------------------------------------------------------------------------
// Purpose: vscript - create a scene directly from a buffer containing
// a vcd description, and load it into the scene entity.
//-----------------------------------------------------------------------------
bool CSceneEntity::ScriptLoadSceneFromString(const char* pszFilename, const char* pszData)
{
CChoreoScene* pScene = new CChoreoScene(NULL);
// CSceneTokenProcessor SceneTokenProcessor;
// SceneTokenProcessor.SetBuffer( pszData );
g_TokenProcessor.SetBuffer((char*)pszData);
if (!pScene->ParseFromBuffer(pszFilename, &g_TokenProcessor)) //&SceneTokenProcessor ) )
{
Warning("CSceneEntity::LoadSceneFromString: Unable to parse scene data '%s'\n", pszFilename);
delete pScene;
pScene = NULL;
}
else
{
pScene->SetPrintFunc(LocalScene_Printf);
pScene->SetEventCallbackInterface(this);
// precache all sounds for the newly constructed scene
PrecacheScene(pScene);
}
if (pScene != NULL)
{
// release prior scene if present
UnloadScene();
m_pScene = pScene;
return true;
}
else
{
return false;
}
}
//-----------------------------------------------------------------------------
// Purpose: Remove all "scene" expressions from all actors in this scene
//-----------------------------------------------------------------------------
@ -4691,6 +4845,44 @@ void CSceneEntity::SetRecipientFilter( IRecipientFilter *filter )
}
}
//-----------------------------------------------------------------------------
// Purpose: Adds a player (by index) to the recipient filter
//-----------------------------------------------------------------------------
void CSceneEntity::AddBroadcastTeamTarget(int nTeamIndex)
{
if (m_pRecipientFilter == NULL)
{
CRecipientFilter filter;
SetRecipientFilter(&filter);
}
CTeam* pTeam = GetGlobalTeam(nTeamIndex);
Assert(pTeam);
if (pTeam == NULL)
return;
m_pRecipientFilter->AddRecipientsByTeam(pTeam);
}
//-----------------------------------------------------------------------------
// Purpose: Removes a player (by index) from the recipient filter
//-----------------------------------------------------------------------------
void CSceneEntity::RemoveBroadcastTeamTarget(int nTeamIndex)
{
if (m_pRecipientFilter == NULL)
{
CRecipientFilter filter;
SetRecipientFilter(&filter);
}
CTeam* pTeam = GetGlobalTeam(nTeamIndex);
Assert(pTeam);
if (pTeam == NULL)
return;
m_pRecipientFilter->RemoveRecipientsByTeam(pTeam);
}
//-----------------------------------------------------------------------------
// Purpose:
@ -4986,6 +5178,26 @@ int GetSceneSpeechCount( char const *pszScene )
return 0;
}
HSCRIPT ScriptCreateSceneEntity( const char* pszScene )
{
if ( IsEntityCreationAllowedInScripts() == false )
{
Warning( "VScript error: A script attempted to create a scene entity mid-game. Entity creation from scripts is only allowed during map init.\n" );
return NULL;
}
g_pScriptVM->RegisterClass( GetScriptDescForClass( CSceneEntity ) );
CSceneEntity *pScene = (CSceneEntity *)CBaseEntity::CreateNoSpawn( "logic_choreographed_scene", vec3_origin, vec3_angle );
if ( pScene )
{
pScene->m_iszSceneFile = AllocPooledString( pszScene );
DispatchSpawn( pScene );
}
return ToHScript( pScene );
}
#ifdef MAPBASE
CON_COMMAND(mapbase_scene_precache, "Just work")
{

View File

@ -48,6 +48,7 @@ int GetSceneSpeechCount( char const *pszScene );
bool IsInInterruptableScenes( CBaseFlex *pActor );
void PrecacheInstancedScene( char const *pszScene );
HSCRIPT ScriptCreateSceneEntity( char const *pszScene );
char const *GetSceneFilename( CBaseEntity *ent );
void ReloadSceneFromDisk( CBaseEntity *ent );

View File

@ -648,6 +648,11 @@ $Project
$File "$SRCDIR\game\shared\voice_common.h"
$File "$SRCDIR\game\shared\voice_gamemgr.cpp"
$File "$SRCDIR\game\shared\voice_gamemgr.h"
$File "vscript_server.cpp"
$File "vscript_server.h"
$File "vscript_server.nut"
$File "$SRCDIR\game\shared\vscript_shared.cpp"
$File "$SRCDIR\game\shared\vscript_shared.h"
$File "waterbullet.cpp"
$File "waterbullet.h"
$File "WaterLODControl.cpp"

View File

@ -2978,94 +2978,6 @@ void CAI_ChangeHintGroup::InputActivate( inputdata_t &inputdata )
#endif
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CTriggerCamera : public CBaseEntity
{
public:
DECLARE_CLASS( CTriggerCamera, CBaseEntity );
#ifdef MAPBASE
CTriggerCamera();
void UpdateOnRemove();
#endif
void Spawn( void );
bool KeyValue( const char *szKeyName, const char *szValue );
void Enable( void );
void Disable( void );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
void FollowTarget( void );
#ifdef MAPBASE
void MoveThink( void );
#endif
void Move(void);
// Always transmit to clients so they know where to move the view to
virtual int UpdateTransmitState();
DECLARE_DATADESC();
// Input handlers
void InputEnable( inputdata_t &inputdata );
void InputDisable( inputdata_t &inputdata );
#ifdef MAPBASE
void InputSetFOV( inputdata_t &inputdata );
void InputSetFOVRate( inputdata_t &inputdata );
#endif
private:
EHANDLE m_hPlayer;
EHANDLE m_hTarget;
// used for moving the camera along a path (rail rides)
CBaseEntity *m_pPath;
string_t m_sPath;
float m_flWait;
float m_flReturnTime;
float m_flStopTime;
float m_moveDistance;
float m_targetSpeed;
float m_initialSpeed;
float m_acceleration;
float m_deceleration;
int m_state;
Vector m_vecMoveDir;
#ifdef MAPBASE
float m_fov;
float m_fovSpeed;
bool m_bDontSetPlayerView;
#endif
string_t m_iszTargetAttachment;
int m_iAttachmentIndex;
bool m_bSnapToGoal;
#if HL2_EPISODIC
bool m_bInterpolatePosition;
// these are interpolation vars used for interpolating the camera over time
Vector m_vStartPos, m_vEndPos;
float m_flInterpStartTime;
const static float kflPosInterpTime; // seconds
#endif
int m_nPlayerButtons;
int m_nOldTakeDamage;
private:
COutputEvent m_OnEndFollow;
#ifdef MAPBASE
COutputEvent m_OnStartFollow;
#endif
};
#if HL2_EPISODIC
const float CTriggerCamera::kflPosInterpTime = 2.0f;
#endif
@ -3127,6 +3039,12 @@ BEGIN_DATADESC( CTriggerCamera )
END_DATADESC()
// VScript: publish class and select members to script language
BEGIN_ENT_SCRIPTDESC( CTriggerCamera, CBaseEntity, "Server-side camera entity" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetFov, "GetFov", "get camera's current fov setting as integer" )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetFov, "SetFov", "set camera's current fov in integer degrees and fov change rate as float" )
END_SCRIPTDESC();
#ifdef MAPBASE
//-----------------------------------------------------------------------------
// Purpose:
@ -3641,6 +3559,59 @@ void CTriggerCamera::FollowTarget( )
Move();
}
void CTriggerCamera::StartCameraShot( const char *pszShotType, CBaseEntity *pSceneEntity, CBaseEntity *pActor1, CBaseEntity *pActor2, float duration )
{
// called from SceneEntity in response to a CChoreoEvent::CAMERA sent from a VCD.
// talk to vscript, start a camera move
HSCRIPT hStartCameraShot = NULL;
// switch to this camera
// Enable();
// get script module associated with this ent, lookup function in module
if( m_iszVScripts != NULL_STRING )
{
hStartCameraShot = m_ScriptScope.LookupFunction( "ScriptStartCameraShot" );
}
// call the script function to begin the camera move
if ( hStartCameraShot )
{
g_pScriptVM->Call( hStartCameraShot, m_ScriptScope, true, NULL, pszShotType, ToHScript(pSceneEntity), ToHScript(pActor1), ToHScript(pActor2), duration );
g_pScriptVM->ReleaseFunction( hStartCameraShot );
}
}
//-----------------------------------------------------------------------------
// Purpose: vscript callback to get the player's fov
//-----------------------------------------------------------------------------
int CTriggerCamera::ScriptGetFov(void)
{
if (m_hPlayer)
{
CBasePlayer* pBasePlayer = (CBasePlayer*)m_hPlayer.Get();
int iFOV = pBasePlayer->GetFOV();
return iFOV;
}
return 0;
}
//-----------------------------------------------------------------------------
// Purpose: vscript callback to slam the player's fov
//-----------------------------------------------------------------------------
void CTriggerCamera::ScriptSetFov(int iFOV, float fovSpeed)
{
if (m_hPlayer)
{
m_fov = iFOV;
m_fovSpeed = fovSpeed;
CBasePlayer* pBasePlayer = (CBasePlayer*)m_hPlayer.Get();
pBasePlayer->SetFOV(this, iFOV, fovSpeed);
}
}
#ifdef MAPBASE
void CTriggerCamera::MoveThink()
{

View File

@ -244,4 +244,98 @@ public:
CUtlVector<EHANDLE> m_hurtEntities;
};
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CTriggerCamera : public CBaseEntity
{
public:
DECLARE_CLASS( CTriggerCamera, CBaseEntity );
// script description
DECLARE_ENT_SCRIPTDESC();
#ifdef MAPBASE
CTriggerCamera();
void UpdateOnRemove();
#endif
void Spawn( void );
bool KeyValue( const char *szKeyName, const char *szValue );
void Enable( void );
void Disable( void );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
void FollowTarget( void );
void StartCameraShot( const char *pszShotType, CBaseEntity *pSceneEntity, CBaseEntity *pActor1, CBaseEntity *pActor2, float duration );
int ScriptGetFov(void);
void ScriptSetFov(int iFOV, float rate);
#ifdef MAPBASE
void MoveThink( void );
#endif
void Move(void);
// Always transmit to clients so they know where to move the view to
virtual int UpdateTransmitState();
DECLARE_DATADESC();
// Input handlers
void InputEnable( inputdata_t &inputdata );
void InputDisable( inputdata_t &inputdata );
#ifdef MAPBASE
void InputSetFOV( inputdata_t &inputdata );
void InputSetFOVRate( inputdata_t &inputdata );
#endif
private:
EHANDLE m_hPlayer;
EHANDLE m_hTarget;
// used for moving the camera along a path (rail rides)
CBaseEntity *m_pPath;
string_t m_sPath;
float m_flWait;
float m_flReturnTime;
float m_flStopTime;
float m_moveDistance;
float m_targetSpeed;
float m_initialSpeed;
float m_acceleration;
float m_deceleration;
int m_state;
Vector m_vecMoveDir;
#ifdef MAPBASE
float m_fov;
float m_fovSpeed;
bool m_bDontSetPlayerView;
#endif
string_t m_iszTargetAttachment;
int m_iAttachmentIndex;
bool m_bSnapToGoal;
#if HL2_EPISODIC
bool m_bInterpolatePosition;
// these are interpolation vars used for interpolating the camera over time
Vector m_vStartPos, m_vEndPos;
float m_flInterpStartTime;
const static float kflPosInterpTime; // seconds
#endif
int m_nPlayerButtons;
int m_nOldTakeDamage;
private:
COutputEvent m_OnEndFollow;
#ifdef MAPBASE
COutputEvent m_OnStartFollow;
#endif
};
#endif // TRIGGERS_H

View File

@ -1959,7 +1959,7 @@ extern "C" void Sys_Error( char *error, ... )
// *mapData - pointer a block of entity map data
// Output : -1 if the entity was not successfully created; 0 on success
//-----------------------------------------------------------------------------
int DispatchSpawn( CBaseEntity *pEntity )
int DispatchSpawn( CBaseEntity *pEntity, bool bRunVScripts )
{
if ( pEntity )
{
@ -1974,6 +1974,12 @@ int DispatchSpawn( CBaseEntity *pEntity )
//pEntity->SetAbsMins( pEntity->GetOrigin() - Vector(1,1,1) );
//pEntity->SetAbsMaxs( pEntity->GetOrigin() + Vector(1,1,1) );
if (bRunVScripts)
{
pEntity->RunVScripts();
pEntity->RunPrecacheScripts();
}
#if defined(TRACK_ENTITY_MEMORY) && defined(USE_MEM_DEBUG)
const char *pszClassname = NULL;
int iClassname = ((CEntityFactoryDictionary*)EntityFactoryDictionary())->m_Factories.Find( pEntity->GetClassname() );
@ -2040,6 +2046,11 @@ int DispatchSpawn( CBaseEntity *pEntity )
}
gEntList.NotifySpawn( pEntity );
if( bRunVScripts )
{
pEntity->RunOnPostSpawnScripts();
}
}
return 0;

View File

@ -237,6 +237,24 @@ CBasePlayer* UTIL_GetLocalPlayer( void );
// get the local player on a listen server
CBasePlayer *UTIL_GetListenServerHost( void );
//-----------------------------------------------------------------------------
// Purpose: Convenience function so we don't have to make this check all over
//-----------------------------------------------------------------------------
static CBasePlayer * UTIL_GetLocalPlayerOrListenServerHost( void )
{
if ( gpGlobals->maxClients > 1 )
{
if ( engine->IsDedicatedServer() )
{
return NULL;
}
return UTIL_GetListenServerHost();
}
return UTIL_GetLocalPlayer();
}
CBasePlayer* UTIL_PlayerByUserId( int userID );
CBasePlayer* UTIL_PlayerByName( const char *name ); // not case sensitive

View File

@ -0,0 +1,787 @@
//========== Copyright © 2008, Valve Corporation, All rights reserved. ========
//
// Purpose:
//
//=============================================================================
#include "cbase.h"
#include "vscript_server.h"
#include "icommandline.h"
#include "tier1/utlbuffer.h"
#include "tier1/fmtstr.h"
#include "filesystem.h"
#include "eventqueue.h"
#include "characterset.h"
#include "sceneentity.h" // for exposing scene precache function
#include "isaverestore.h"
#include "gamerules.h"
#ifdef _WIN32
//#include "vscript_server_nut.h"
#endif
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
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
class CScriptEntityIterator
{
public:
HSCRIPT First() { return Next(NULL); }
HSCRIPT Next( HSCRIPT hStartEntity )
{
return ToHScript( gEntList.NextEnt( ToEnt( hStartEntity ) ) );
}
HSCRIPT CreateByClassname( const char *className )
{
return ToHScript( CreateEntityByName( className ) );
}
HSCRIPT FindByClassname( HSCRIPT hStartEntity, const char *szName )
{
return ToHScript( gEntList.FindEntityByClassname( ToEnt( hStartEntity ), szName ) );
}
HSCRIPT FindByName( HSCRIPT hStartEntity, const char *szName )
{
return ToHScript( gEntList.FindEntityByName( ToEnt( hStartEntity ), szName ) );
}
HSCRIPT FindInSphere( HSCRIPT hStartEntity, const Vector &vecCenter, float flRadius )
{
return ToHScript( gEntList.FindEntityInSphere( ToEnt( hStartEntity ), vecCenter, flRadius ) );
}
HSCRIPT FindByTarget( HSCRIPT hStartEntity, const char *szName )
{
return ToHScript( gEntList.FindEntityByTarget( ToEnt( hStartEntity ), szName ) );
}
HSCRIPT FindByModel( HSCRIPT hStartEntity, const char *szModelName )
{
return ToHScript( gEntList.FindEntityByModel( ToEnt( hStartEntity ), szModelName ) );
}
HSCRIPT FindByNameNearest( const char *szName, const Vector &vecSrc, float flRadius )
{
return ToHScript( gEntList.FindEntityByNameNearest( szName, vecSrc, flRadius ) );
}
HSCRIPT FindByNameWithin( HSCRIPT hStartEntity, const char *szName, const Vector &vecSrc, float flRadius )
{
return ToHScript( gEntList.FindEntityByNameWithin( ToEnt( hStartEntity ), szName, vecSrc, flRadius ) );
}
HSCRIPT FindByClassnameNearest( const char *szName, const Vector &vecSrc, float flRadius )
{
return ToHScript( gEntList.FindEntityByClassnameNearest( szName, vecSrc, flRadius ) );
}
HSCRIPT FindByClassnameWithin( HSCRIPT hStartEntity , const char *szName, const Vector &vecSrc, float flRadius )
{
return ToHScript( gEntList.FindEntityByClassnameWithin( ToEnt( hStartEntity ), szName, vecSrc, flRadius ) );
}
private:
} g_ScriptEntityIterator;
BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptEntityIterator, "CEntities", SCRIPT_SINGLETON "The global list of entities" )
DEFINE_SCRIPTFUNC( First, "Begin an iteration over the list of entities" )
DEFINE_SCRIPTFUNC( Next, "Continue an iteration over the list of entities, providing reference to a previously found entity" )
DEFINE_SCRIPTFUNC( CreateByClassname, "Creates an entity by classname" )
DEFINE_SCRIPTFUNC( FindByClassname, "Find entities by class name. Pass 'null' to start an iteration, or reference to a previously found entity to continue a search" )
DEFINE_SCRIPTFUNC( FindByName, "Find entities by name. Pass 'null' to start an iteration, or reference to a previously found entity to continue a search" )
DEFINE_SCRIPTFUNC( FindInSphere, "Find entities within a radius. Pass 'null' to start an iteration, or reference to a previously found entity to continue a search" )
DEFINE_SCRIPTFUNC( FindByTarget, "Find entities by targetname. Pass 'null' to start an iteration, or reference to a previously found entity to continue a search" )
DEFINE_SCRIPTFUNC( FindByModel, "Find entities by model name. Pass 'null' to start an iteration, or reference to a previously found entity to continue a search" )
DEFINE_SCRIPTFUNC( FindByNameNearest, "Find entities by name nearest to a point." )
DEFINE_SCRIPTFUNC( FindByNameWithin, "Find entities by name within a radius. Pass 'null' to start an iteration, or reference to a previously found entity to continue a search" )
DEFINE_SCRIPTFUNC( FindByClassnameNearest, "Find entities by class name nearest to a point." )
DEFINE_SCRIPTFUNC( FindByClassnameWithin, "Find entities by class name within a radius. Pass 'null' to start an iteration, or reference to a previously found entity to continue a search" )
END_SCRIPTDESC();
// ----------------------------------------------------------------------------
// KeyValues access - CBaseEntity::ScriptGetKeyFromModel returns root KeyValues
// ----------------------------------------------------------------------------
BEGIN_SCRIPTDESC_ROOT( CScriptKeyValues, "Wrapper class over KeyValues instance" )
DEFINE_SCRIPT_CONSTRUCTOR()
DEFINE_SCRIPTFUNC_NAMED( ScriptFindKey, "FindKey", "Given a KeyValues object and a key name, find a KeyValues object associated with the key name" );
DEFINE_SCRIPTFUNC_NAMED( ScriptGetFirstSubKey, "GetFirstSubKey", "Given a KeyValues object, return the first sub key object" );
DEFINE_SCRIPTFUNC_NAMED( ScriptGetNextKey, "GetNextKey", "Given a KeyValues object, return the next key object in a sub key group" );
DEFINE_SCRIPTFUNC_NAMED( ScriptGetKeyValueInt, "GetKeyInt", "Given a KeyValues object and a key name, return associated integer value" );
DEFINE_SCRIPTFUNC_NAMED( ScriptGetKeyValueFloat, "GetKeyFloat", "Given a KeyValues object and a key name, return associated float value" );
DEFINE_SCRIPTFUNC_NAMED( ScriptGetKeyValueBool, "GetKeyBool", "Given a KeyValues object and a key name, return associated bool value" );
DEFINE_SCRIPTFUNC_NAMED( ScriptGetKeyValueString, "GetKeyString", "Given a KeyValues object and a key name, return associated string value" );
DEFINE_SCRIPTFUNC_NAMED( ScriptIsKeyValueEmpty, "IsKeyEmpty", "Given a KeyValues object and a key name, return true if key name has no value" );
DEFINE_SCRIPTFUNC_NAMED( ScriptReleaseKeyValues, "ReleaseKeyValues", "Given a root KeyValues object, release its contents" );
END_SCRIPTDESC();
HSCRIPT CScriptKeyValues::ScriptFindKey( const char *pszName )
{
KeyValues *pKeyValues = m_pKeyValues->FindKey(pszName);
if ( pKeyValues == NULL )
return NULL;
CScriptKeyValues *pScriptKey = new CScriptKeyValues( pKeyValues );
// UNDONE: who calls ReleaseInstance on this??
HSCRIPT hScriptInstance = g_pScriptVM->RegisterInstance( pScriptKey );
return hScriptInstance;
}
HSCRIPT CScriptKeyValues::ScriptGetFirstSubKey( void )
{
KeyValues *pKeyValues = m_pKeyValues->GetFirstSubKey();
if ( pKeyValues == NULL )
return NULL;
CScriptKeyValues *pScriptKey = new CScriptKeyValues( pKeyValues );
// UNDONE: who calls ReleaseInstance on this??
HSCRIPT hScriptInstance = g_pScriptVM->RegisterInstance( pScriptKey );
return hScriptInstance;
}
HSCRIPT CScriptKeyValues::ScriptGetNextKey( void )
{
KeyValues *pKeyValues = m_pKeyValues->GetNextKey();
if ( pKeyValues == NULL )
return NULL;
CScriptKeyValues *pScriptKey = new CScriptKeyValues( pKeyValues );
// UNDONE: who calls ReleaseInstance on this??
HSCRIPT hScriptInstance = g_pScriptVM->RegisterInstance( pScriptKey );
return hScriptInstance;
}
int CScriptKeyValues::ScriptGetKeyValueInt( const char *pszName )
{
int i = m_pKeyValues->GetInt( pszName );
return i;
}
float CScriptKeyValues::ScriptGetKeyValueFloat( const char *pszName )
{
float f = m_pKeyValues->GetFloat( pszName );
return f;
}
const char *CScriptKeyValues::ScriptGetKeyValueString( const char *pszName )
{
const char *psz = m_pKeyValues->GetString( pszName );
return psz;
}
bool CScriptKeyValues::ScriptIsKeyValueEmpty( const char *pszName )
{
bool b = m_pKeyValues->IsEmpty( pszName );
return b;
}
bool CScriptKeyValues::ScriptGetKeyValueBool( const char *pszName )
{
bool b = m_pKeyValues->GetBool( pszName );
return b;
}
void CScriptKeyValues::ScriptReleaseKeyValues( )
{
m_pKeyValues->deleteThis();
m_pKeyValues = NULL;
}
// constructors
CScriptKeyValues::CScriptKeyValues( KeyValues *pKeyValues = NULL )
{
m_pKeyValues = pKeyValues;
}
// destructor
CScriptKeyValues::~CScriptKeyValues( )
{
if (m_pKeyValues)
{
m_pKeyValues->deleteThis();
}
m_pKeyValues = NULL;
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
static float Time()
{
return gpGlobals->curtime;
}
static float FrameTime()
{
return gpGlobals->frametime;
}
static void SendToConsole( const char *pszCommand )
{
CBasePlayer *pPlayer = UTIL_GetLocalPlayerOrListenServerHost();
if ( !pPlayer )
{
DevMsg ("Cannot execute \"%s\", no player\n", pszCommand );
return;
}
engine->ClientCommand( pPlayer->edict(), pszCommand );
}
static const char *GetMapName()
{
return STRING( gpGlobals->mapname );
}
static const char *DoUniqueString( const char *pszBase )
{
static char szBuf[512];
g_pScriptVM->GenerateUniqueKey( pszBase, szBuf, ARRAYSIZE(szBuf) );
return szBuf;
}
static void DoEntFire( const char *pszTarget, const char *pszAction, const char *pszValue, float delay, HSCRIPT hActivator, HSCRIPT hCaller )
{
const char *target = "", *action = "Use";
variant_t value;
target = STRING( AllocPooledString( pszTarget ) );
// Don't allow them to run anything on a point_servercommand unless they're the host player. Otherwise they can ent_fire
// and run any command on the server. Admittedly, they can only do the ent_fire if sv_cheats is on, but
// people complained about users resetting the rcon password if the server briefly turned on cheats like this:
// give point_servercommand
// ent_fire point_servercommand command "rcon_password mynewpassword"
if ( gpGlobals->maxClients > 1 && V_stricmp( target, "point_servercommand" ) == 0 )
{
return;
}
if ( *pszAction )
{
action = STRING( AllocPooledString( pszAction ) );
}
if ( *pszValue )
{
value.SetString( AllocPooledString( pszValue ) );
}
if ( delay < 0 )
{
delay = 0;
}
g_EventQueue.AddEvent( target, action, value, delay, ToEnt(hActivator), ToEnt(hCaller) );
}
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;
}
HSCRIPT CreateProp( const char *pszEntityName, const Vector &vOrigin, const char *pszModelName, int iAnim )
{
CBaseAnimating *pBaseEntity = (CBaseAnimating *)CreateEntityByName( pszEntityName );
pBaseEntity->SetAbsOrigin( vOrigin );
pBaseEntity->SetModel( pszModelName );
pBaseEntity->SetPlaybackRate( 1.0f );
int iSequence = pBaseEntity->SelectWeightedSequence( (Activity)iAnim );
if ( iSequence != -1 )
{
pBaseEntity->SetSequence( iSequence );
}
return ToHScript( pBaseEntity );
}
//--------------------------------------------------------------------------------------------------
// Use an entity's script instance to add an entity IO event (used for firing events on unnamed entities from vscript)
//--------------------------------------------------------------------------------------------------
static void DoEntFireByInstanceHandle( HSCRIPT hTarget, const char *pszAction, const char *pszValue, float delay, HSCRIPT hActivator, HSCRIPT hCaller )
{
const char *action = "Use";
variant_t value;
if ( *pszAction )
{
action = STRING( AllocPooledString( pszAction ) );
}
if ( *pszValue )
{
value.SetString( AllocPooledString( pszValue ) );
}
if ( delay < 0 )
{
delay = 0;
}
CBaseEntity* pTarget = ToEnt(hTarget);
if ( !pTarget )
{
Warning( "VScript error: DoEntFire was passed an invalid entity instance.\n" );
return;
}
g_EventQueue.AddEvent( pTarget, action, value, delay, ToEnt(hActivator), ToEnt(hCaller) );
}
static float ScriptTraceLine( const Vector &vecStart, const Vector &vecEnd, HSCRIPT entIgnore )
{
// UTIL_TraceLine( vecAbsStart, vecAbsEnd, MASK_BLOCKLOS, pLooker, COLLISION_GROUP_NONE, ptr );
trace_t tr;
CBaseEntity *pLooker = ToEnt(entIgnore);
UTIL_TraceLine( vecStart, vecEnd, MASK_NPCWORLDSTATIC, pLooker, COLLISION_GROUP_NONE, &tr);
if (tr.fractionleftsolid && tr.startsolid)
{
return 1.0 - tr.fractionleftsolid;
}
else
{
return tr.fraction;
}
}
bool VScriptServerInit()
{
VMPROF_START
if( scriptmanager != NULL )
{
ScriptLanguage_t scriptLanguage = SL_DEFAULT;
char const *pszScriptLanguage;
if ( CommandLine()->CheckParm( "-scriptlang", &pszScriptLanguage ) )
{
if( !Q_stricmp(pszScriptLanguage, "gamemonkey") )
{
scriptLanguage = SL_GAMEMONKEY;
}
else if( !Q_stricmp(pszScriptLanguage, "squirrel") )
{
scriptLanguage = SL_SQUIRREL;
}
else if( !Q_stricmp(pszScriptLanguage, "python") )
{
scriptLanguage = SL_PYTHON;
}
else
{
DevWarning("-server_script does not recognize a language named '%s'. virtual machine did NOT start.\n", pszScriptLanguage );
scriptLanguage = SL_NONE;
}
}
if( scriptLanguage != SL_NONE )
{
if ( g_pScriptVM == NULL )
g_pScriptVM = scriptmanager->CreateVM( scriptLanguage );
if( g_pScriptVM )
{
Log( "VSCRIPT: Started VScript virtual machine using script language '%s'\n", g_pScriptVM->GetLanguageName() );
ScriptRegisterFunctionNamed( g_pScriptVM, UTIL_ShowMessageAll, "ShowMessage", "Print a hud message on all clients" );
ScriptRegisterFunction( g_pScriptVM, SendToConsole, "Send a string to the console as a command" );
ScriptRegisterFunction( g_pScriptVM, GetMapName, "Get the name of the map.");
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptTraceLine, "TraceLine", "given 2 points & ent to ignore, return fraction along line that hits world or models" );
ScriptRegisterFunction( g_pScriptVM, Time, "Get the current server time" );
ScriptRegisterFunction( g_pScriptVM, FrameTime, "Get the time spent on the server in the last frame" );
ScriptRegisterFunction( g_pScriptVM, DoEntFire, SCRIPT_ALIAS( "EntFire", "Generate and entity i/o event" ) );
ScriptRegisterFunctionNamed( g_pScriptVM, DoEntFireByInstanceHandle, "EntFireByHandle", "Generate and entity i/o event. First parameter is an entity 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." ) );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptCreateSceneEntity, "CreateSceneEntity", "Create a scene entity to play the specified scene." );
ScriptRegisterFunctionNamed( g_pScriptVM, NDebugOverlay::Box, "DebugDrawBox", "Draw a debug overlay box" );
ScriptRegisterFunctionNamed( g_pScriptVM, NDebugOverlay::Line, "DebugDrawLine", "Draw a debug overlay box" );
ScriptRegisterFunction( g_pScriptVM, DoIncludeScript, "Execute a script (internal)" );
ScriptRegisterFunction( g_pScriptVM, CreateProp, "Create a physics prop" );
if ( GameRules() )
{
GameRules()->RegisterScriptFunctions();
}
g_pScriptVM->RegisterInstance( &g_ScriptEntityIterator, "Entities" );
if ( scriptLanguage == SL_SQUIRREL )
{
//g_pScriptVM->Run( g_Script_vscript_server );
}
VScriptRunScript( "mapspawn", false );
VMPROF_SHOW( pszScriptLanguage, "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 VScriptServerTerm()
{
if( g_pScriptVM != NULL )
{
if( g_pScriptVM )
{
scriptmanager->DestroyVM( g_pScriptVM );
g_pScriptVM = NULL;
}
}
}
bool VScriptServerReplaceClosures( const char *pszScriptName, HSCRIPT hScope, bool bWarnMissing )
{
if ( !g_pScriptVM )
{
return false;
}
HSCRIPT hReplaceClosuresFunc = g_pScriptVM->LookupFunction( "__ReplaceClosures" );
if ( !hReplaceClosuresFunc )
{
return false;
}
HSCRIPT hNewScript = VScriptCompileScript( pszScriptName, bWarnMissing );
if ( !hNewScript )
{
return false;
}
g_pScriptVM->Call( hReplaceClosuresFunc, NULL, true, NULL, hNewScript, hScope );
return true;
}
CON_COMMAND( script_reload_code, "Execute a vscript file, replacing existing functions with the functions in the run script" )
{
if ( !*args[1] )
{
Warning( "No script specified\n" );
return;
}
if ( !g_pScriptVM )
{
Warning( "Scripting disabled or no server running\n" );
return;
}
VScriptServerReplaceClosures( args[1], NULL, true );
}
CON_COMMAND( script_reload_entity_code, "Execute all of this entity's VScripts, replacing existing functions with the functions in the run scripts" )
{
extern CBaseEntity *GetNextCommandEntity( CBasePlayer *pPlayer, const char *name, CBaseEntity *ent );
const char *pszTarget = "";
if ( *args[1] )
{
pszTarget = args[1];
}
if ( !g_pScriptVM )
{
Warning( "Scripting disabled or no server running\n" );
return;
}
CBasePlayer *pPlayer = UTIL_GetCommandClient();
if ( !pPlayer )
return;
CBaseEntity *pEntity = NULL;
while ( (pEntity = GetNextCommandEntity( pPlayer, pszTarget, pEntity )) != NULL )
{
if ( pEntity->m_ScriptScope.IsInitialized() && pEntity->m_iszVScripts != NULL_STRING )
{
char szScriptsList[255];
Q_strcpy( szScriptsList, STRING(pEntity->m_iszVScripts) );
CUtlStringList szScripts;
V_SplitString( szScriptsList, " ", szScripts);
for( int i = 0 ; i < szScripts.Count() ; i++ )
{
VScriptServerReplaceClosures( szScripts[i], pEntity->m_ScriptScope, true );
}
}
}
}
CON_COMMAND( script_reload_think, "Execute an activation script, replacing existing functions with the functions in the run script" )
{
extern CBaseEntity *GetNextCommandEntity( CBasePlayer *pPlayer, const char *name, CBaseEntity *ent );
const char *pszTarget = "";
if ( *args[1] )
{
pszTarget = args[1];
}
if ( !g_pScriptVM )
{
Warning( "Scripting disabled or no server running\n" );
return;
}
CBasePlayer *pPlayer = UTIL_GetCommandClient();
if ( !pPlayer )
return;
CBaseEntity *pEntity = NULL;
while ( (pEntity = GetNextCommandEntity( pPlayer, pszTarget, pEntity )) != NULL )
{
if ( pEntity->m_ScriptScope.IsInitialized() && pEntity->m_iszScriptThinkFunction != NULL_STRING )
{
VScriptServerReplaceClosures( STRING(pEntity->m_iszScriptThinkFunction), pEntity->m_ScriptScope, true );
}
}
}
class CVScriptGameSystem : public CAutoGameSystemPerFrame
{
public:
// Inherited from IAutoServerSystem
virtual void LevelInitPreEntity( void )
{
m_bAllowEntityCreationInScripts = true;
VScriptServerInit();
}
virtual void LevelInitPostEntity( void )
{
m_bAllowEntityCreationInScripts = false;
}
virtual void LevelShutdownPostEntity( void )
{
VScriptServerTerm();
}
virtual void FrameUpdatePostEntityThink()
{
if ( g_pScriptVM )
g_pScriptVM->Frame( gpGlobals->frametime );
}
bool m_bAllowEntityCreationInScripts;
};
CVScriptGameSystem g_VScriptGameSystem;
bool IsEntityCreationAllowedInScripts( void )
{
return g_VScriptGameSystem.m_bAllowEntityCreationInScripts;
}
static short VSCRIPT_SERVER_SAVE_RESTORE_VERSION = 2;
//-----------------------------------------------------------------------------
class CVScriptSaveRestoreBlockHandler : public CDefSaveRestoreBlockHandler
{
public:
CVScriptSaveRestoreBlockHandler() :
m_InstanceMap( DefLessFunc(const char *) )
{
}
const char *GetBlockName()
{
return "VScriptServer";
}
//---------------------------------
void Save( ISave *pSave )
{
pSave->StartBlock();
int temp = g_pScriptVM != NULL;
pSave->WriteInt( &temp );
if ( g_pScriptVM )
{
temp = g_pScriptVM->GetLanguage();
pSave->WriteInt( &temp );
CUtlBuffer buffer;
g_pScriptVM->WriteState( &buffer );
temp = buffer.TellPut();
pSave->WriteInt( &temp );
if ( temp > 0 )
{
pSave->WriteData( (const char *)buffer.Base(), temp );
}
}
pSave->EndBlock();
}
//---------------------------------
void WriteSaveHeaders( ISave *pSave )
{
pSave->WriteShort( &VSCRIPT_SERVER_SAVE_RESTORE_VERSION );
}
//---------------------------------
void ReadRestoreHeaders( IRestore *pRestore )
{
// No reason why any future version shouldn't try to retain backward compatability. The default here is to not do so.
short version;
pRestore->ReadShort( &version );
m_fDoLoad = ( version == VSCRIPT_SERVER_SAVE_RESTORE_VERSION );
}
//---------------------------------
void Restore( IRestore *pRestore, bool createPlayers )
{
if ( !m_fDoLoad && g_pScriptVM )
{
return;
}
CBaseEntity *pEnt = gEntList.FirstEnt();
while ( pEnt )
{
if ( pEnt->m_iszScriptId != NULL_STRING )
{
g_pScriptVM->RegisterClass( pEnt->GetScriptDesc() );
m_InstanceMap.Insert( STRING( pEnt->m_iszScriptId ), pEnt );
}
pEnt = gEntList.NextEnt( pEnt );
}
pRestore->StartBlock();
if ( pRestore->ReadInt() && pRestore->ReadInt() == g_pScriptVM->GetLanguage() )
{
int nBytes = pRestore->ReadInt();
if ( nBytes > 0 )
{
CUtlBuffer buffer;
buffer.EnsureCapacity( nBytes );
pRestore->ReadData( (char *)buffer.AccessForDirectRead( nBytes ), nBytes, 0 );
g_pScriptVM->ReadState( &buffer );
}
}
pRestore->EndBlock();
}
void PostRestore( void )
{
for ( int i = m_InstanceMap.FirstInorder(); i != m_InstanceMap.InvalidIndex(); i = m_InstanceMap.NextInorder( i ) )
{
CBaseEntity *pEnt = m_InstanceMap[i];
if ( pEnt->m_hScriptInstance )
{
ScriptVariant_t variant;
if ( g_pScriptVM->GetValue( STRING(pEnt->m_iszScriptId), &variant ) && variant.m_type == FIELD_HSCRIPT )
{
pEnt->m_ScriptScope.Init( variant.m_hScript, false );
pEnt->RunPrecacheScripts();
}
}
else
{
// Script system probably has no internal references
pEnt->m_iszScriptId = NULL_STRING;
}
}
m_InstanceMap.Purge();
}
CUtlMap<const char *, CBaseEntity *> m_InstanceMap;
private:
bool m_fDoLoad;
};
//-----------------------------------------------------------------------------
CVScriptSaveRestoreBlockHandler g_VScriptSaveRestoreBlockHandler;
//-------------------------------------
ISaveRestoreBlockHandler *GetVScriptSaveRestoreBlockHandler()
{
return &g_VScriptSaveRestoreBlockHandler;
}
//-----------------------------------------------------------------------------
bool CBaseEntityScriptInstanceHelper::ToString( void *p, char *pBuf, int bufSize )
{
CBaseEntity *pEntity = (CBaseEntity *)p;
if ( pEntity->GetEntityName() != NULL_STRING )
{
V_snprintf( pBuf, bufSize, "([%d] %s: %s)", pEntity->entindex(), STRING(pEntity->m_iClassname), STRING( pEntity->GetEntityName() ) );
}
else
{
V_snprintf( pBuf, bufSize, "([%d] %s)", pEntity->entindex(), STRING(pEntity->m_iClassname) );
}
return true;
}
void *CBaseEntityScriptInstanceHelper::BindOnRead( HSCRIPT hInstance, void *pOld, const char *pszId )
{
int iEntity = g_VScriptSaveRestoreBlockHandler.m_InstanceMap.Find( pszId );
if ( iEntity != g_VScriptSaveRestoreBlockHandler.m_InstanceMap.InvalidIndex() )
{
CBaseEntity *pEnt = g_VScriptSaveRestoreBlockHandler.m_InstanceMap[iEntity];
pEnt->m_hScriptInstance = hInstance;
return pEnt;
}
return NULL;
}
CBaseEntityScriptInstanceHelper g_BaseEntityScriptInstanceHelper;

View File

@ -0,0 +1,57 @@
//========== Copyright © 2008, Valve Corporation, All rights reserved. ========
//
// Purpose:
//
//=============================================================================
#ifndef VSCRIPT_SERVER_H
#define VSCRIPT_SERVER_H
#include "vscript/ivscript.h"
#include "tier1/KeyValues.h"
#include "vscript_shared.h"
#if defined( _WIN32 )
#pragma once
#endif
class ISaveRestoreBlockHandler;
bool VScriptServerReplaceClosures( const char *pszScriptName, HSCRIPT hScope, bool bWarnMissing = false );
ISaveRestoreBlockHandler *GetVScriptSaveRestoreBlockHandler();
class CBaseEntityScriptInstanceHelper : public IScriptInstanceHelper
{
bool ToString( void *p, char *pBuf, int bufSize );
void *BindOnRead( HSCRIPT hInstance, void *pOld, const char *pszId );
};
extern CBaseEntityScriptInstanceHelper g_BaseEntityScriptInstanceHelper;
// Only allow scripts to create entities during map initialization
bool IsEntityCreationAllowedInScripts( void );
// ----------------------------------------------------------------------------
// KeyValues access
// ----------------------------------------------------------------------------
class CScriptKeyValues
{
public:
CScriptKeyValues( KeyValues *pKeyValues );
~CScriptKeyValues( );
HSCRIPT ScriptFindKey( const char *pszName );
HSCRIPT ScriptGetFirstSubKey( void );
HSCRIPT ScriptGetNextKey( void );
int ScriptGetKeyValueInt( const char *pszName );
float ScriptGetKeyValueFloat( const char *pszName );
const char *ScriptGetKeyValueString( const char *pszName );
bool ScriptIsKeyValueEmpty( const char *pszName );
bool ScriptGetKeyValueBool( const char *pszName );
void ScriptReleaseKeyValues( );
KeyValues *m_pKeyValues; // actual KeyValue entity
};
#endif // VSCRIPT_SERVER_H

View File

@ -0,0 +1,127 @@
//========== Copyright © 2008, Valve Corporation, All rights reserved. ========
//
// Purpose:
//
//=============================================================================
function UniqueString( string = "" )
{
return DoUniqueString( string.tostring() );
}
function EntFire( target, action, value = null, delay = 0.0, activator = null )
{
if ( !value )
{
value = "";
}
local caller = null;
if ( "self" in this )
{
caller = self;
if ( !activator )
{
activator = self;
}
}
DoEntFire( target.tostring(), action.tostring(), value.tostring(), delay, activator, caller );
}
function __ReplaceClosures( script, scope )
{
if ( !scope )
{
scope = getroottable();
}
local tempParent = { getroottable = function() { return null; } };
local temp = { runscript = script };
delegate tempParent : temp;
temp.runscript()
foreach( key,val in temp )
{
if ( typeof(val) == "function" && key != "runscript" )
{
printl( " Replacing " + key );
scope[key] <- val;
}
}
}
__OutputsPattern <- regexp("^On.*Output$");
function ConnectOutputs( table )
{
const nCharsToStrip = 6;
foreach( key, val in table )
{
if ( typeof( val ) == "function" && __OutputsPattern.match( key ) )
{
//printl(key.slice( 0, nCharsToStrip ) );
table.self.ConnectOutput( key.slice( 0, key.len() - nCharsToStrip ), key );
}
}
}
function IncludeScript( name, scope = null )
{
if ( scope == null )
{
scope = this;
}
return ::DoIncludeScript( name, scope );
}
//---------------------------------------------------------
// Text dump this scope's contents to the console.
//---------------------------------------------------------
function __DumpScope( depth, table )
{
local indent=function( count )
{
local i;
for( i = 0 ; i < count ; i++ )
{
print(" ");
}
}
foreach(key, value in table)
{
indent(depth);
print( key );
switch (type(value))
{
case "table":
print("(TABLE)\n");
indent(depth);
print("{\n");
__DumpScope( depth + 1, value);
indent(depth);
print("}");
break;
case "array":
print("(ARRAY)\n");
indent(depth);
print("[\n")
__DumpScope( depth + 1, value);
indent(depth);
print("]");
break;
case "string":
print(" = \"");
print(value);
print("\"");
break;
default:
print(" = ");
print(value);
break;
}
print("\n");
}
}

View File

@ -1217,6 +1217,19 @@ void CBaseEntity::EmitSound( const char *soundname, HSOUNDSCRIPTHANDLE& handle,
EmitSound( filter, entindex(), params, handle );
}
#if !defined ( CLIENT_DLL )
void CBaseEntity::ScriptEmitSound( const char *soundname )
{
EmitSound( soundname );
}
float CBaseEntity::ScriptSoundDuration( const char *soundname, const char *actormodel )
{
float duration = CBaseEntity::GetSoundDuration( soundname, actormodel );
return duration;
}
#endif // !CLIENT
//-----------------------------------------------------------------------------
// Purpose:
// Input : filter -
@ -1486,6 +1499,14 @@ HSOUNDSCRIPTHANDLE CBaseEntity::PrecacheScriptSound( const char *soundname )
#endif
}
#if !defined ( CLIENT_DLL )
// Same as server version of above, but signiture changed so it can be deduced by the macros
void CBaseEntity::VScriptPrecacheScriptSound(const char* soundname)
{
g_SoundEmitterSystem.PrecacheScriptSound(soundname);
}
#endif // !CLIENT_DLL
void CBaseEntity::PrefetchScriptSound( const char *soundname )
{
g_SoundEmitterSystem.PrefetchScriptSound( soundname );

View File

@ -68,6 +68,9 @@ enum InvalidatePhysicsBits_t
#endif
#include "vscript/ivscript.h"
#include "vscript_shared.h"
#if !defined( NO_ENTITY_PREDICTION )
// CBaseEntity inlines
inline bool CBaseEntity::IsPlayerSimulated( void ) const
@ -247,6 +250,17 @@ inline bool CBaseEntity::IsEffectActive( int nEffects ) const
return (m_fEffects & nEffects) != 0;
}
inline HSCRIPT ToHScript(CBaseEntity* pEnt)
{
return (pEnt) ? pEnt->GetScriptInstance() : NULL;
}
template <> ScriptClassDesc_t* GetScriptDesc<CBaseEntity>(CBaseEntity*);
inline CBaseEntity* ToEnt(HSCRIPT hScript)
{
return (hScript) ? (CBaseEntity*)g_pScriptVM->GetInstanceValue(hScript, GetScriptDescForClass(CBaseEntity)) : NULL;
}
// Shared EntityMessage between game and client .dlls
#define BASEENTITY_MSG_REMOVE_DECALS 1

View File

@ -2064,6 +2064,8 @@ static EventNameMap_t g_NameMap[] =
{ CChoreoEvent::STOPPOINT, "stoppoint" },
{ CChoreoEvent::PERMIT_RESPONSES, "permitresponses" },
{ CChoreoEvent::GENERIC, "generic" },
{ CChoreoEvent::CAMERA, "camera" },
{ CChoreoEvent::SCRIPT, "script" },
};
//-----------------------------------------------------------------------------

View File

@ -307,6 +307,12 @@ public:
// A string passed to the game code for interpretation
GENERIC,
// Camera control
CAMERA,
// Script function call
SCRIPT,
// THIS MUST BE LAST!!!
NUM_TYPES,
} EVENTTYPE;

View File

@ -173,6 +173,8 @@ public:
virtual bool InRoundRestart( void ) { return false; }
virtual void RegisterScriptFunctions( void ){ };
//Allow thirdperson camera.
virtual bool AllowThirdPersonCamera( void ) { return false; }

View File

@ -36,6 +36,7 @@ public:
m_pEvent( 0 ),
m_pScene( 0 ),
m_pActor( 0 ),
m_hSceneEntity(0),
m_bStarted( false ),
m_iLayer( -1 ),
m_iPriority( 0 ),
@ -63,6 +64,8 @@ public:
// Current actor
CChoreoActor *m_pActor;
CHandle< CSceneEntity > m_hSceneEntity;
// Set after the first time the event has been configured ( allows
// bumping markov index only at start of event playback, not every frame )
bool m_bStarted;

View File

@ -0,0 +1,266 @@
//========== Copyright © 2008, Valve Corporation, All rights reserved. ========
//
// Purpose:
//
//=============================================================================
#include "cbase.h"
#include "vscript_shared.h"
#include "icommandline.h"
#include "tier1/utlbuffer.h"
#include "tier1/fmtstr.h"
#include "filesystem.h"
#include "characterset.h"
#include "isaverestore.h"
#include "gamerules.h"
IScriptVM * g_pScriptVM;
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
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.sprintf( "scripts/vscripts/%s", pszScriptName );
}
else
{
scriptPath.sprintf( "scripts/vscripts/%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
{
bool bResult = filesystem->ReadFile( scriptPath, "GAME", bufferScript );
if( !bResult )
{
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_ScriptServerRunScriptDepth;
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_ScriptServerRunScriptDepth > 16 )
{
Warning( "IncludeScript stack overflow\n" );
return false;
}
g_ScriptServerRunScriptDepth++;
HSCRIPT hScript = VScriptCompileScript( pszScriptName, bWarnMissing );
bool bSuccess = false;
if ( hScript )
{
#ifdef GAME_DLL
if ( gpGlobals->maxClients == 1 )
{
CBaseEntity *pPlayer = UTIL_GetLocalPlayer();
if ( pPlayer )
{
g_pScriptVM->SetValue( "player", pPlayer->GetScriptInstance() );
}
}
#endif
bSuccess = ( g_pScriptVM->Run( hScript, hScope ) != SCRIPT_ERROR );
if ( !bSuccess )
{
Warning( "Error running script named %s\n", pszScriptName );
Assert( "Error running script" );
}
}
g_ScriptServerRunScriptDepth--;
return bSuccess;
}
#ifdef CLIENT_DLL
CON_COMMAND( script_client, "Run the text as a script" )
#else
CON_COMMAND( script, "Run the text as a script" )
#endif
{
if ( !*args[1] )
{
Warning( "No function name specified\n" );
return;
}
if ( !g_pScriptVM )
{
Warning( "Scripting disabled or no server running\n" );
return;
}
const char *pszScript = args.GetCommandString();
#ifdef CLIENT_DLL
pszScript += 13;
#else
pszScript += 6;
#endif
while ( *pszScript == ' ' )
{
pszScript++;
}
if ( !*pszScript )
{
return;
}
if ( *pszScript != '\"' )
{
g_pScriptVM->Run( pszScript );
}
else
{
pszScript++;
const char *pszEndQuote = pszScript;
while ( *pszEndQuote != '\"' )
{
pszEndQuote++;
}
if ( !*pszEndQuote )
{
return;
}
*((char *)pszEndQuote) = 0;
g_pScriptVM->Run( pszScript );
*((char *)pszEndQuote) = '\"';
}
}
CON_COMMAND_SHARED( script_execute, "Run a vscript file" )
{
if ( !*args[1] )
{
Warning( "No script specified\n" );
return;
}
if ( !g_pScriptVM )
{
Warning( "Scripting disabled or no server running\n" );
return;
}
VScriptRunScript( args[1], true );
}
CON_COMMAND_SHARED( script_debug, "Connect the vscript VM to the script debugger" )
{
if ( !g_pScriptVM )
{
Warning( "Scripting disabled or no server running\n" );
return;
}
g_pScriptVM->ConnectDebugger();
}
CON_COMMAND_SHARED( script_help, "Output help for script functions, optionally with a search string" )
{
if ( !g_pScriptVM )
{
Warning( "Scripting disabled or no server running\n" );
return;
}
const char *pszArg1 = "*";
if ( *args[1] )
{
pszArg1 = args[1];
}
g_pScriptVM->Run( CFmtStr( "PrintHelp( \"%s\" );", pszArg1 ) );
}
CON_COMMAND_SHARED( script_dump_all, "Dump the state of the VM to the console" )
{
if ( !g_pScriptVM )
{
Warning( "Scripting disabled or no server running\n" );
return;
}
g_pScriptVM->DumpState();
}

View File

@ -0,0 +1,34 @@
//========== Copyright © 2008, Valve Corporation, All rights reserved. ========
//
// Purpose:
//
//=============================================================================
#ifndef VSCRIPT_SHARED_H
#define VSCRIPT_SHARED_H
#include "vscript/ivscript.h"
#if defined( _WIN32 )
#pragma once
#endif
extern IScriptVM * g_pScriptVM;
HSCRIPT VScriptCompileScript( const char *pszScriptName, bool bWarnMissing = false );
bool VScriptRunScript( const char *pszScriptName, HSCRIPT hScope, bool bWarnMissing = false );
inline bool VScriptRunScript( const char *pszScriptName, bool bWarnMissing = false ) { return VScriptRunScript( pszScriptName, NULL, bWarnMissing ); }
#define DECLARE_ENT_SCRIPTDESC() ALLOW_SCRIPT_ACCESS(); virtual ScriptClassDesc_t *GetScriptDesc()
#define BEGIN_ENT_SCRIPTDESC( className, baseClass, description ) _IMPLEMENT_ENT_SCRIPTDESC_ACCESSOR( className ); BEGIN_SCRIPTDESC( className, baseClass, description )
#define BEGIN_ENT_SCRIPTDESC_ROOT( className, description ) _IMPLEMENT_ENT_SCRIPTDESC_ACCESSOR( className ); BEGIN_SCRIPTDESC_ROOT( className, description )
#define BEGIN_ENT_SCRIPTDESC_NAMED( className, baseClass, scriptName, description ) _IMPLEMENT_ENT_SCRIPTDESC_ACCESSOR( className ); BEGIN_SCRIPTDESC_NAMED( className, baseClass, scriptName, description )
#define BEGIN_ENT_SCRIPTDESC_ROOT_NAMED( className, scriptName, description ) _IMPLEMENT_ENT_SCRIPTDESC_ACCESSOR( className ); BEGIN_SCRIPTDESC_ROOT_NAMED( className, scriptName, description )
#define _IMPLEMENT_ENT_SCRIPTDESC_ACCESSOR( className ) template <> ScriptClassDesc_t * GetScriptDesc<className>( className * ); ScriptClassDesc_t *className::GetScriptDesc() { return ::GetScriptDesc( this ); }
// Only allow scripts to create entities during map initialization
bool IsEntityCreationAllowedInScripts( void );
#endif // VSCRIPT_SHARED_H

View File

@ -632,6 +632,18 @@ private:
static ConCommand name##_command( #name, name, description ); \
static void name( const CCommand &args )
#ifdef CLIENT_DLL
#define CON_COMMAND_SHARED( name, description ) \
static void name( const CCommand &args ); \
static ConCommand name##_command_client( #name "_client", name, description ); \
static void name( const CCommand &args )
#else
#define CON_COMMAND_SHARED( name, description ) \
static void name( const CCommand &args ); \
static ConCommand name##_command( #name, name, description ); \
static void name( const CCommand &args )
#endif
#define CON_COMMAND_F( name, description, flags ) \
static void name( const CCommand &args ); \
static ConCommand name##_command( #name, name, description, flags ); \

View File

@ -142,6 +142,9 @@ public:
// Makes sure we've got at least this much memory
void EnsureCapacity( int num );
// Access for direct read into buffer
void * AccessForDirectRead( int nBytes );
// Attaches the buffer to external memory....
void SetExternalBuffer( void* pMemory, int nSize, int nInitialPut, int nFlags = 0 );
@ -1096,5 +1099,13 @@ inline void CUtlBuffer::CopyBuffer( const void *pubData, int cubData )
}
}
inline void *CUtlBuffer::AccessForDirectRead( int nBytes )
{
Assert( m_Get == 0 && m_Put == 0 && m_nMaxPut == 0 );
EnsureCapacity( nBytes );
m_nMaxPut = nBytes;
return Base();
}
#endif // UTLBUFFER_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,414 @@
//========== Copyright © 2008, Valve Corporation, All rights reserved. ========
//
// Purpose:
//
//=============================================================================
#ifndef VSCRIPT_TEMPLATES_H
#define VSCRIPT_TEMPLATES_H
#include "tier0/basetypes.h"
#if defined( _WIN32 )
#pragma once
#endif
#define FUNC_APPEND_PARAMS_0
#define FUNC_APPEND_PARAMS_1 pDesc->m_Parameters.SetGrowSize( 1 ); pDesc->m_Parameters.EnsureCapacity( 1 ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_1 ) );
#define FUNC_APPEND_PARAMS_2 pDesc->m_Parameters.SetGrowSize( 1 ); pDesc->m_Parameters.EnsureCapacity( 2 ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_1 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_2 ) );
#define FUNC_APPEND_PARAMS_3 pDesc->m_Parameters.SetGrowSize( 1 ); pDesc->m_Parameters.EnsureCapacity( 3 ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_1 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_2 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_3 ) );
#define FUNC_APPEND_PARAMS_4 pDesc->m_Parameters.SetGrowSize( 1 ); pDesc->m_Parameters.EnsureCapacity( 4 ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_1 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_2 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_3 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_4 ) );
#define FUNC_APPEND_PARAMS_5 pDesc->m_Parameters.SetGrowSize( 1 ); pDesc->m_Parameters.EnsureCapacity( 5 ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_1 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_2 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_3 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_4 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_5 ) );
#define FUNC_APPEND_PARAMS_6 pDesc->m_Parameters.SetGrowSize( 1 ); pDesc->m_Parameters.EnsureCapacity( 6 ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_1 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_2 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_3 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_4 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_5 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_6 ) );
#define FUNC_APPEND_PARAMS_7 pDesc->m_Parameters.SetGrowSize( 1 ); pDesc->m_Parameters.EnsureCapacity( 7 ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_1 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_2 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_3 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_4 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_5 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_6 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_7 ) );
#define FUNC_APPEND_PARAMS_8 pDesc->m_Parameters.SetGrowSize( 1 ); pDesc->m_Parameters.EnsureCapacity( 8 ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_1 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_2 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_3 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_4 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_5 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_6 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_7 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_8 ) );
#define FUNC_APPEND_PARAMS_9 pDesc->m_Parameters.SetGrowSize( 1 ); pDesc->m_Parameters.EnsureCapacity( 9 ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_1 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_2 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_3 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_4 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_5 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_6 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_7 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_8 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_9 ) );
#define FUNC_APPEND_PARAMS_10 pDesc->m_Parameters.SetGrowSize( 1 ); pDesc->m_Parameters.EnsureCapacity( 10 ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_1 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_2 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_3 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_4 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_5 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_6 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_7 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_8 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_9 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_10 ) );
#define FUNC_APPEND_PARAMS_11 pDesc->m_Parameters.SetGrowSize( 1 ); pDesc->m_Parameters.EnsureCapacity( 11 ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_1 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_2 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_3 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_4 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_5 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_6 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_7 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_8 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_9 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_10 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_11 ) );
#define FUNC_APPEND_PARAMS_12 pDesc->m_Parameters.SetGrowSize( 1 ); pDesc->m_Parameters.EnsureCapacity( 12 ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_1 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_2 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_3 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_4 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_5 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_6 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_7 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_8 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_9 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_10 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_11 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_12 ) );
#define FUNC_APPEND_PARAMS_13 pDesc->m_Parameters.SetGrowSize( 1 ); pDesc->m_Parameters.EnsureCapacity( 13 ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_1 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_2 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_3 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_4 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_5 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_6 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_7 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_8 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_9 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_10 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_11 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_12 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_13 ) );
#define FUNC_APPEND_PARAMS_14 pDesc->m_Parameters.SetGrowSize( 1 ); pDesc->m_Parameters.EnsureCapacity( 14 ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_1 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_2 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_3 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_4 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_5 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_6 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_7 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_8 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_9 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_10 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_11 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_12 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_13 ) ); pDesc->m_Parameters.AddToTail( ScriptDeduceType( FUNC_ARG_TYPE_14 ) );
#define DEFINE_NONMEMBER_FUNC_TYPE_DEDUCER(N) \
template <typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N> \
inline void ScriptDeduceFunctionSignature(ScriptFuncDescriptor_t *pDesc, FUNCTION_RETTYPE (*pfnProxied)( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) ) \
{ \
pDesc->m_ReturnType = ScriptDeduceType(FUNCTION_RETTYPE); \
FUNC_APPEND_PARAMS_##N \
}
FUNC_GENERATE_ALL( DEFINE_NONMEMBER_FUNC_TYPE_DEDUCER );
#define DEFINE_MEMBER_FUNC_TYPE_DEDUCER(N) \
template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N> \
inline void ScriptDeduceFunctionSignature(ScriptFuncDescriptor_t *pDesc, OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) ) \
{ \
pDesc->m_ReturnType = ScriptDeduceType(FUNCTION_RETTYPE); \
FUNC_APPEND_PARAMS_##N \
}
FUNC_GENERATE_ALL( DEFINE_MEMBER_FUNC_TYPE_DEDUCER );
//-------------------------------------
#define DEFINE_CONST_MEMBER_FUNC_TYPE_DEDUCER(N) \
template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N> \
inline void ScriptDeduceFunctionSignature(ScriptFuncDescriptor_t *pDesc, OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const ) \
{ \
pDesc->m_ReturnType = ScriptDeduceType(FUNCTION_RETTYPE); \
FUNC_APPEND_PARAMS_##N \
}
FUNC_GENERATE_ALL( DEFINE_CONST_MEMBER_FUNC_TYPE_DEDUCER );
#define ScriptInitMemberFuncDescriptor_( pDesc, class, func, scriptName ) if ( 0 ) {} else { (pDesc)->m_pszScriptName = scriptName; (pDesc)->m_pszFunction = #func; ScriptDeduceFunctionSignature( pDesc, (class *)(0), &class::func ); }
#define ScriptInitFuncDescriptorNamed( pDesc, func, scriptName ) if ( 0 ) {} else { (pDesc)->m_pszScriptName = scriptName; (pDesc)->m_pszFunction = #func; ScriptDeduceFunctionSignature( pDesc, &func ); }
#define ScriptInitFuncDescriptor( pDesc, func ) ScriptInitFuncDescriptorNamed( pDesc, func, #func )
#define ScriptInitMemberFuncDescriptorNamed( pDesc, class, func, scriptName ) ScriptInitMemberFuncDescriptor_( pDesc, class, func, scriptName )
#define ScriptInitMemberFuncDescriptor( pDesc, class, func ) ScriptInitMemberFuncDescriptorNamed( pDesc, class, func, #func )
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
template <typename FUNCPTR_TYPE>
inline void *ScriptConvertFuncPtrToVoid( FUNCPTR_TYPE pFunc )
{
if ( ( sizeof( FUNCPTR_TYPE ) == sizeof( void * ) ) )
{
union FuncPtrConvert
{
void *p;
FUNCPTR_TYPE pFunc;
};
FuncPtrConvert convert;
convert.pFunc = pFunc;
return convert.p;
}
#if defined( _MSC_VER )
else if ( ( sizeof( FUNCPTR_TYPE ) == sizeof( void * ) + sizeof( int ) ) )
{
struct MicrosoftUnknownMFP
{
void *p;
int m_delta;
};
union FuncPtrConvertMI
{
MicrosoftUnknownMFP mfp;
FUNCPTR_TYPE pFunc;
};
FuncPtrConvertMI convert;
convert.pFunc = pFunc;
if ( convert.mfp.m_delta == 0 )
{
return convert.mfp.p;
}
AssertMsg( 0, "Function pointer must be from primary vtable" );
}
else if ( ( sizeof( FUNCPTR_TYPE ) == sizeof( void * ) + ( sizeof( int ) * 3 ) ) )
{
struct MicrosoftUnknownMFP
{
void *p;
int m_delta;
int m_vtordisp;
int m_vtable_index;
};
union FuncPtrConvertMI
{
MicrosoftUnknownMFP mfp;
FUNCPTR_TYPE pFunc;
};
FuncPtrConvertMI convert;
convert.pFunc = pFunc;
if ( convert.mfp.m_delta == 0 )
{
return convert.mfp.p;
}
AssertMsg( 0, "Function pointer must be from primary vtable" );
}
#elif defined( GNUC )
else if ( ( sizeof( FUNCPTR_TYPE ) == sizeof( void * ) + sizeof( int ) ) )
{
AssertMsg( 0, "Note: This path has not been verified yet. See comments below in #else case." );
struct GnuMFP
{
union
{
void *funcadr; // If vtable_index_2 is even, then this is the function pointer.
int vtable_index_2; // If vtable_index_2 is odd, then this = vindex*2+1.
};
int delta;
};
GnuMFP *p = (GnuMFP*)&pFunc;
if ( p->vtable_index_2 & 1 )
{
char **delta = (char**)p->delta;
char *pCur = *delta + (p->vtable_index_2+1)/2;
return (void*)( pCur + 4 );
}
else
{
return p->funcadr;
}
}
#else
#error "Need to implement code to crack non-offset member function pointer case"
// For gcc, see: http://www.codeproject.com/KB/cpp/FastDelegate.aspx
//
// Current versions of the GNU compiler use a strange and tricky
// optimization. It observes that, for virtual inheritance, you have to look
// up the vtable in order to get the voffset required to calculate the this
// pointer. While you're doing that, you might as well store the function
// pointer in the vtable. By doing this, they combine the m_func_address and
// m_vtable_index fields into one, and they distinguish between them by
// ensuring that function pointers always point to even addresses but vtable
// indices are always odd:
//
// // GNU g++ uses a tricky space optimisation, also adopted by IBM's VisualAge and XLC.
// struct GnuMFP {
// union {
// CODEPTR funcadr; // always even
// int vtable_index_2; // = vindex*2+1, always odd
// };
// int delta;
// };
// adjustedthis = this + delta
// if (funcadr & 1) CALL (* ( *delta + (vindex+1)/2) + 4)
// else CALL funcadr
//
// The G++ method is well documented, so it has been adopted by many other
// vendors, including IBM's VisualAge and XLC compilers, recent versions of
// Open64, Pathscale EKO, and Metrowerks' 64-bit compilers. A simpler scheme
// used by earlier versions of GCC is also very common. SGI's now
// discontinued MIPSPro and Pro64 compilers, and Apple's ancient MrCpp
// compiler used this method. (Note that the Pro64 compiler has become the
// open source Open64 compiler).
#endif
else
AssertMsg( 0, "Member function pointer not supported. Why on earth are you using virtual inheritance!?" );
return NULL;
}
template <typename FUNCPTR_TYPE>
inline FUNCPTR_TYPE ScriptConvertFuncPtrFromVoid( void *p )
{
if ( ( sizeof( FUNCPTR_TYPE ) == sizeof( void * ) ) )
{
union FuncPtrConvert
{
void *p;
FUNCPTR_TYPE pFunc;
};
FuncPtrConvert convert;
convert.p = p;
return convert.pFunc;
}
#if defined( _MSC_VER )
if ( ( sizeof( FUNCPTR_TYPE ) == sizeof( void * ) + sizeof( int ) ) )
{
struct MicrosoftUnknownMFP
{
void *p;
int m_delta;
};
union FuncPtrConvertMI
{
MicrosoftUnknownMFP mfp;
FUNCPTR_TYPE pFunc;
};
FuncPtrConvertMI convert;
convert.mfp.p = p;
convert.mfp.m_delta = 0;
return convert.pFunc;
}
if ( ( sizeof( FUNCPTR_TYPE ) == sizeof( void * ) + ( sizeof( int ) * 3 ) ) )
{
struct MicrosoftUnknownMFP
{
void *p;
int m_delta;
int m_vtordisp;
int m_vtable_index;
};
union FuncPtrConvertMI
{
MicrosoftUnknownMFP mfp;
FUNCPTR_TYPE pFunc;
};
FuncPtrConvertMI convert;
convert.mfp.p = p;
convert.mfp.m_delta = 0;
return convert.pFunc;
}
#elif defined( POSIX )
AssertMsg( 0, "Note: This path has not been implemented yet." );
#else
#error "Need to implement code to crack non-offset member function pointer case"
#endif
Assert( 0 );
return NULL;
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_PASSTHRU_0
#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_PASSTHRU_1 , FUNC_BASE_TEMPLATE_FUNC_PARAMS_1
#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_PASSTHRU_2 , FUNC_BASE_TEMPLATE_FUNC_PARAMS_2
#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_PASSTHRU_3 , FUNC_BASE_TEMPLATE_FUNC_PARAMS_3
#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_PASSTHRU_4 , FUNC_BASE_TEMPLATE_FUNC_PARAMS_4
#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_PASSTHRU_5 , FUNC_BASE_TEMPLATE_FUNC_PARAMS_5
#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_PASSTHRU_6 , FUNC_BASE_TEMPLATE_FUNC_PARAMS_6
#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_PASSTHRU_7 , FUNC_BASE_TEMPLATE_FUNC_PARAMS_7
#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_PASSTHRU_8 , FUNC_BASE_TEMPLATE_FUNC_PARAMS_8
#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_PASSTHRU_9 , FUNC_BASE_TEMPLATE_FUNC_PARAMS_9
#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_PASSTHRU_10 , FUNC_BASE_TEMPLATE_FUNC_PARAMS_10
#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_PASSTHRU_11 , FUNC_BASE_TEMPLATE_FUNC_PARAMS_11
#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_PASSTHRU_12 , FUNC_BASE_TEMPLATE_FUNC_PARAMS_12
#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_PASSTHRU_13 , FUNC_BASE_TEMPLATE_FUNC_PARAMS_13
#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_PASSTHRU_14 , FUNC_BASE_TEMPLATE_FUNC_PARAMS_14
#define SCRIPT_BINDING_ARGS_0
#define SCRIPT_BINDING_ARGS_1 pArguments[0]
#define SCRIPT_BINDING_ARGS_2 pArguments[0], pArguments[1]
#define SCRIPT_BINDING_ARGS_3 pArguments[0], pArguments[1], pArguments[2]
#define SCRIPT_BINDING_ARGS_4 pArguments[0], pArguments[1], pArguments[2], pArguments[3]
#define SCRIPT_BINDING_ARGS_5 pArguments[0], pArguments[1], pArguments[2], pArguments[3], pArguments[4]
#define SCRIPT_BINDING_ARGS_6 pArguments[0], pArguments[1], pArguments[2], pArguments[3], pArguments[4], pArguments[5]
#define SCRIPT_BINDING_ARGS_7 pArguments[0], pArguments[1], pArguments[2], pArguments[3], pArguments[4], pArguments[5], pArguments[6]
#define SCRIPT_BINDING_ARGS_8 pArguments[0], pArguments[1], pArguments[2], pArguments[3], pArguments[4], pArguments[5], pArguments[6], pArguments[7]
#define SCRIPT_BINDING_ARGS_9 pArguments[0], pArguments[1], pArguments[2], pArguments[3], pArguments[4], pArguments[5], pArguments[6], pArguments[7], pArguments[8]
#define SCRIPT_BINDING_ARGS_10 pArguments[0], pArguments[1], pArguments[2], pArguments[3], pArguments[4], pArguments[5], pArguments[6], pArguments[7], pArguments[8], pArguments[9]
#define SCRIPT_BINDING_ARGS_11 pArguments[0], pArguments[1], pArguments[2], pArguments[3], pArguments[4], pArguments[5], pArguments[6], pArguments[7], pArguments[8], pArguments[9], pArguments[10]
#define SCRIPT_BINDING_ARGS_12 pArguments[0], pArguments[1], pArguments[2], pArguments[3], pArguments[4], pArguments[5], pArguments[6], pArguments[7], pArguments[8], pArguments[9], pArguments[10], pArguments[11]
#define SCRIPT_BINDING_ARGS_13 pArguments[0], pArguments[1], pArguments[2], pArguments[3], pArguments[4], pArguments[5], pArguments[6], pArguments[7], pArguments[8], pArguments[9], pArguments[10], pArguments[11], pArguments[12]
#define SCRIPT_BINDING_ARGS_14 pArguments[0], pArguments[1], pArguments[2], pArguments[3], pArguments[4], pArguments[5], pArguments[6], pArguments[7], pArguments[8], pArguments[9], pArguments[10], pArguments[11], pArguments[12], pArguments[13]
#define DEFINE_SCRIPT_BINDINGS(N) \
template <typename FUNC_TYPE, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N> \
class CNonMemberScriptBinding##N \
{ \
public: \
static bool Call( void *pFunction, void *pContext, ScriptVariant_t *pArguments, int nArguments, ScriptVariant_t *pReturn ) \
{ \
Assert( nArguments == N ); \
Assert( pReturn ); \
Assert( !pContext ); \
\
if ( nArguments != N || !pReturn || pContext ) \
{ \
return false; \
} \
*pReturn = ((FUNC_TYPE)pFunction)( SCRIPT_BINDING_ARGS_##N ); \
if ( pReturn->m_type == FIELD_VECTOR ) \
pReturn->m_pVector = new Vector(*pReturn->m_pVector); \
return true; \
} \
}; \
\
template <typename FUNC_TYPE FUNC_TEMPLATE_FUNC_PARAMS_##N> \
class CNonMemberScriptBinding##N<FUNC_TYPE, void FUNC_BASE_TEMPLATE_FUNC_PARAMS_PASSTHRU_##N> \
{ \
public: \
static bool Call( void *pFunction, void *pContext, ScriptVariant_t *pArguments, int nArguments, ScriptVariant_t *pReturn ) \
{ \
Assert( nArguments == N ); \
Assert( !pReturn ); \
Assert( !pContext ); \
\
if ( nArguments != N || pReturn || pContext ) \
{ \
return false; \
} \
((FUNC_TYPE)pFunction)( SCRIPT_BINDING_ARGS_##N ); \
return true; \
} \
}; \
\
template <class OBJECT_TYPE_PTR, typename FUNC_TYPE, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N> \
class CMemberScriptBinding##N \
{ \
public: \
static bool Call( void *pFunction, void *pContext, ScriptVariant_t *pArguments, int nArguments, ScriptVariant_t *pReturn ) \
{ \
Assert( nArguments == N ); \
Assert( pReturn ); \
Assert( pContext ); \
\
if ( nArguments != N || !pReturn || !pContext ) \
{ \
return false; \
} \
*pReturn = (((OBJECT_TYPE_PTR)(pContext))->*ScriptConvertFuncPtrFromVoid<FUNC_TYPE>(pFunction))( SCRIPT_BINDING_ARGS_##N ); \
if ( pReturn->m_type == FIELD_VECTOR ) \
pReturn->m_pVector = new Vector(*pReturn->m_pVector); \
return true; \
} \
}; \
\
template <class OBJECT_TYPE_PTR, typename FUNC_TYPE FUNC_TEMPLATE_FUNC_PARAMS_##N> \
class CMemberScriptBinding##N<OBJECT_TYPE_PTR, FUNC_TYPE, void FUNC_BASE_TEMPLATE_FUNC_PARAMS_PASSTHRU_##N> \
{ \
public: \
static bool Call( void *pFunction, void *pContext, ScriptVariant_t *pArguments, int nArguments, ScriptVariant_t *pReturn ) \
{ \
Assert( nArguments == N ); \
Assert( !pReturn ); \
Assert( pContext ); \
\
if ( nArguments != N || pReturn || !pContext ) \
{ \
return false; \
} \
(((OBJECT_TYPE_PTR)(pContext))->*ScriptConvertFuncPtrFromVoid<FUNC_TYPE>(pFunction))( SCRIPT_BINDING_ARGS_##N ); \
return true; \
} \
}; \
\
template <typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N> \
inline ScriptBindingFunc_t ScriptCreateBinding(FUNCTION_RETTYPE (*pfnProxied)( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) ) \
{ \
typedef FUNCTION_RETTYPE (*Func_t)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N); \
return &CNonMemberScriptBinding##N<Func_t, FUNCTION_RETTYPE FUNC_BASE_TEMPLATE_FUNC_PARAMS_PASSTHRU_##N>::Call; \
} \
\
template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N> \
inline ScriptBindingFunc_t ScriptCreateBinding(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE (FUNCTION_CLASS::*pfnProxied)( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) ) \
{ \
typedef FUNCTION_RETTYPE (FUNCTION_CLASS::*Func_t)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N); \
return &CMemberScriptBinding##N<OBJECT_TYPE_PTR, Func_t, FUNCTION_RETTYPE FUNC_BASE_TEMPLATE_FUNC_PARAMS_PASSTHRU_##N>::Call; \
} \
\
template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N> \
inline ScriptBindingFunc_t ScriptCreateBinding(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE (FUNCTION_CLASS::*pfnProxied)( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const ) \
{ \
typedef FUNCTION_RETTYPE (FUNCTION_CLASS::*Func_t)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N); \
return &CMemberScriptBinding##N<OBJECT_TYPE_PTR, Func_t, FUNCTION_RETTYPE FUNC_BASE_TEMPLATE_FUNC_PARAMS_PASSTHRU_##N>::Call; \
}
FUNC_GENERATE_ALL( DEFINE_SCRIPT_BINDINGS );
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
#endif // VSCRIPT_TEMPLATES_H