Merge pull request #5 from ReDucTor/wip/vscript_support

WIP: vscript support
This commit is contained in:
Blixibon 2020-05-22 17:56:00 -05:00 committed by GitHub
commit 2dbaa2c4a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
206 changed files with 33799 additions and 135 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) ),
@ -1095,6 +1106,8 @@ bool C_BaseEntity::Init( int entnum, int iSerialNum )
m_nCreationTick = gpGlobals->tickcount;
m_hScriptInstance = NULL;
return true;
}
@ -1165,6 +1178,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 +1215,12 @@ void C_BaseEntity::Term()
RemoveFromLeafSystem();
RemoveFromAimEntsList();
if ( m_hScriptInstance )
{
g_pScriptVM->RemoveInstance( m_hScriptInstance );
m_hScriptInstance = NULL;
}
}
@ -6442,6 +6462,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,16 @@ int CHLClient::Init( CreateInterfaceFn appSystemFactory, CreateInterfaceFn physi
if (!g_pMatSystemSurface)
return false;
if ( !CommandLine()->CheckParm( "-noscripting") )
{
scriptmanager = (IScriptManager *)appSystemFactory( VSCRIPT_INTERFACE_VERSION, NULL );
if (scriptmanager == nullptr)
{
scriptmanager = (IScriptManager*)Sys_GetFactoryThis()(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

@ -11,6 +11,8 @@ $Configuration
$PreprocessorDefinitions "$BASE;ASW_PROJECTED_TEXTURES;DYNAMIC_RTT_SHADOWS"
$PreprocessorDefinitions "$BASE;MAPBASE_RPC;DISCORD_RPC;STEAM_RPC" [$MAPBASE_RPC]
$PreprocessorDefinitions "$BASE;MAPBASE_VSCRIPT" [$MAPBASE_VSCRIPT]
}
}
@ -51,4 +53,9 @@ $Project
}
}
}
$Folder "Link Libraries"
{
$Lib "vscript" [$MAPBASE_VSCRIPT]
}
}

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 )
{
@ -1325,14 +1343,13 @@ void CBaseEntity::FireNamedOutput( const char *pszOutput, variant_t variant, CBa
CBaseEntityOutput *pOutput = ( CBaseEntityOutput * )( ( int )this + ( int )dataDesc->fieldOffset[0] );
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
@ -6978,6 +7147,7 @@ const char *CBaseEntity::GetContextValue( int index ) const
}
return m_ResponseContexts[ index ].m_iszValue.ToCStr();
}
//-----------------------------------------------------------------------------
@ -7223,7 +7393,6 @@ void CBaseEntity::InputPassRandomUser( inputdata_t& inputdata )
}
#endif
#ifdef MAPBASE
//-----------------------------------------------------------------------------
// Purpose: Sets the entity's targetname.
@ -7820,6 +7989,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 +9215,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,16 @@ 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 (scriptmanager == nullptr)
{
scriptmanager = (IScriptManager*)Sys_GetFactoryThis()(VSCRIPT_INTERFACE_VERSION, NULL);
}
}
// If not running dedicated, grab the engine vgui interface
if ( !engine->IsDedicatedServer() )
{
@ -684,6 +698,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 +777,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, "Group15"),
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()
@ -345,7 +347,7 @@ bool CPointTemplate::CreateInstance( const Vector &vecOrigin, const QAngle &vecA
// Some templates have Entity I/O connecting the entities within the template.
// Unique versions of these templates need to be created whenever they're instanced.
if ( AllowNameFixup() && Templates_IndexRequiresEntityIOFixup( iTemplateIndex ) )
if ( AllowNameFixup() && ( Templates_IndexRequiresEntityIOFixup( iTemplateIndex ) || m_ScriptScope.IsInitialized() ) )
{
// This template requires instancing.
// Create a new mapdata block and ask the template system to fill it in with
@ -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;
}
@ -426,7 +436,7 @@ bool CPointTemplate::CreateSpecificInstance( int iTemplate, const Vector &vecOri
// Some templates have Entity I/O connecting the entities within the template.
// Unique versions of these templates need to be created whenever they're instanced.
if ( AllowNameFixup() && Templates_IndexRequiresEntityIOFixup( iTemplateIndex ) )
if ( AllowNameFixup() && ( Templates_IndexRequiresEntityIOFixup( iTemplateIndex ) || m_ScriptScope.IsInitialized() ) )
{
// This template requires instancing.
// Create a new mapdata block and ask the template system to fill it in with
@ -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

@ -9,6 +9,8 @@ $Configuration
$Compiler
{
$PreprocessorDefinitions "$BASE;ASW_PROJECTED_TEXTURES;DYNAMIC_RTT_SHADOWS"
$PreprocessorDefinitions "$BASE;MAPBASE_VSCRIPT" [$MAPBASE_VSCRIPT]
}
}
@ -81,4 +83,9 @@ $Project
}
}
}
$Folder "Link Libraries"
{
$Lib "vscript" [$MAPBASE_VSCRIPT]
}
}

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,272 @@
//========== 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
#ifdef MAPBASE_VSCRIPT
// This is to ensure a dependency exists between the vscript library and the game DLLs
extern int vscript_token;
int vscript_token_hack = vscript_token;
#endif
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

View File

@ -51,6 +51,7 @@ $Group "everything"
"vice"
"vrad_dll"
"vrad_launcher"
"vscript"
"vtf2tga"
"vtfdiff"
"vvis_dll"

View File

@ -111,6 +111,11 @@ $Project "vrad_launcher"
"utils\vrad_launcher\vrad_launcher.vpc" [$WIN32]
}
$Project "vscript"
{
"vscript\vscript.vpc"
}
$Project "vtf2tga"
{
"utils\vtf2tga\vtf2tga.vpc" [$WIN32]

View File

@ -21,6 +21,9 @@ $Conditional MAPBASE "1"
// Toggles Mapbase's RPC implementation
$Conditional MAPBASE_RPC "1"
// Toggles VScript implementation (note: interfaces still exist, just the provided implementation is not present)
$Conditional MAPBASE_VSCRIPT "1"
//-----------------------------------------------------------------------------
$Configuration "Debug"

6
sp/src/vscript/squirrel/.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
# Folders created at compilation
bin/
lib/
# Folders created at documentation generation
doc/build/

View File

@ -0,0 +1,17 @@
language: cpp
compiler:
- gcc
- clang
# Travis VMs are 64-bit but we compile both for 32 and 64 bit. To enable the
# 32-bit builds to work, we need gcc-multilib.
addons:
apt:
packages:
- gcc-multilib
- g++-multilib
# Enable container-based builds.
sudo: false
script: mkdir build && cd build && cmake .. && make -j2

View File

@ -0,0 +1,109 @@
cmake_minimum_required(VERSION 3.4)
project(squirrel VERSION 3.1 LANGUAGES C CXX)
option(DISABLE_STATIC "Avoid building/installing static libraries.")
option(LONG_OUTPUT_NAMES "Use longer names for binaries and libraries: squirrel3 (not sq).")
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release")
endif ()
include(GNUInstallDirs)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}")
set(CMAKE_CXX_STANDARD 11)
if(CMAKE_COMPILER_IS_GNUCXX)
add_compile_options(
"$<$<COMPILE_LANGUAGE:CXX>:-fno-rtti;-fno-exceptions>"
-fno-strict-aliasing
-Wall
-Wextra
-pedantic
-Wcast-qual
"$<$<CONFIG:Release>:-O3>"
"$<$<CONFIG:RelWithDebInfo>:-O3;-g>"
"$<$<CONFIG:MinSizeRel>:-Os>"
"$<$<CONFIG:Debug>:-pg;-pie;-gstabs;-g3;-Og>"
)
elseif(MSVC)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
endif()
add_subdirectory(squirrel)
add_subdirectory(sqstdlib)
add_subdirectory(sq)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(tgts)
if(NOT DISABLE_DYNAMIC)
list(APPEND tgts squirrel sqstdlib sq)
endif()
if(NOT DISABLE_STATIC)
list(APPEND tgts squirrel_static sqstdlib_static sq_static)
endif()
foreach(t ${tgts})
target_compile_definitions(${t} PUBLIC -D_SQ64)
endforeach()
endif()
if(NOT DISABLE_DYNAMIC)
set_target_properties(squirrel sqstdlib PROPERTIES SOVERSION 0 VERSION 0.0.0)
endif()
if(NOT SQ_DISABLE_INSTALLER AND NOT SQ_DISABLE_HEADER_INSTALLER)
install(FILES
include/sqconfig.h
include/squirrel.h
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
COMPONENT Development
)
install(FILES
include/sqstdaux.h
include/sqstdblob.h
include/sqstdio.h
include/sqstdmath.h
include/sqstdstring.h
include/sqstdsystem.h
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
COMPONENT Development
)
endif()
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}/cmake/squirrel/squirrel-config-version.cmake"
VERSION "${squirrel_VERSION}"
COMPATIBILITY AnyNewerVersion
)
configure_package_config_file(
"${CMAKE_CURRENT_SOURCE_DIR}/squirrel-config.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}/cmake/squirrel/squirrel-config.cmake"
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/squirrel"
)
export(EXPORT squirrel
NAMESPACE squirrel::
FILE "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}/cmake/squirrel/squirrel-targets.cmake"
)
if(NOT SQ_DISABLE_INSTALLER AND NOT SQ_DISABLE_CMAKE_INSTALLER)
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}/cmake/squirrel/squirrel-config-version.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}/cmake/squirrel/squirrel-config.cmake"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/squirrel"
COMPONENT Development
)
install(EXPORT squirrel
NAMESPACE squirrel::
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/squirrel"
FILE "squirrel-targets.cmake"
COMPONENT Development
)
endif()

View File

@ -0,0 +1,86 @@
Squirrel 3.1 stable
--------------------------------------------------------
What is in this distribution?
squirrel
static library implementing the compiler and interpreter of the language
sqstdlib
the standard utility libraries
sq
stand alone interpreter
doc
The manual
etc
a minimalistic embedding sample
samples
samples programs
HOW TO COMPILE
---------------------------------------------------------
CMAKE USERS
.........................................................
If you want to build the shared libraries under Windows using Visual
Studio, you will have to use CMake version 3.4 or newer. If not, an
earlier version will suffice. For a traditional out-of-source build
under Linux, type something like
$ mkdir build # Create temporary build directory
$ cd build
$ cmake .. # CMake will determine all the necessary information,
# including the platform (32- vs. 64-bit)
$ make
$ make install
$ cd ..; rm -r build
The default installation directory will be /usr/local on Unix platforms,
and C:/Program Files/squirrel on Windows. The binaries will go into bin/
and the libraries into lib/. You can change this behavior by calling CMake like
this:
$ cmake .. -DCMAKE_INSTALL_PREFIX=/some/path/on/your/system
With the CMAKE_INSTALL_BINDIR and CMAKE_INSTALL_LIBDIR options, the directories
the binaries & libraries will go in (relative to CMAKE_INSTALL_PREFIX)
can be specified. For instance,
$ cmake .. -DCMAKE_INSTALL_LIBDIR=lib64
will install the libraries into a 'lib64' subdirectory in the top
source directory. The public header files will be installed into the directory
the value of CMAKE_INSTALL_INCLUDEDIR points to. If you want only the
binaries and no headers, just set -DSQ_DISABLE_HEADER_INSTALLER=ON, and no
header files will be installed.
Under Windows, it is probably easiest to use the CMake GUI interface,
although invoking CMake from the command line as explained above
should work as well.
GCC USERS
.........................................................
There is a very simple makefile that compiles all libraries and exes
from the root of the project run 'make'
for 32 bits systems
$ make
for 64 bits systems
$ make sq64
VISUAL C++ USERS
.........................................................
Open squirrel.dsw from the root project directory and build(dho!)
DOCUMENTATION GENERATION
.........................................................
To be able to compile the documentation, make sure that you have Python
installed and the packages sphinx and sphinx_rtd_theme. Browse into doc/
and use either the Makefile for GCC-based platforms or make.bat for
Windows platforms.

View File

@ -0,0 +1,21 @@
Copyright (c) 2003-2017 Alberto Demichelis
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------
END OF COPYRIGHT

View File

@ -0,0 +1,533 @@
***version 3.2 stable***
-added sq_tailcall
-added rawcall keyword
-added post call initializer syntax
-added table.keys() and table.values()
-added table.filter()
-additional parameters in array.map() and array.apply()
-additional optional initializer in array.reduce()
-closure.call() is now a "native tailcall" and the invoked function can now be suspended
-fixed sq_newmember and sq_rawnewmember properly pop parameters
-fixed capturing free variable on for loop counter before a break statement
-fixed \u in lexer
-various bugfixes
***version 3.1.1 stable***
-sq_gettypetag doesn't set last error(it's treated as SQBool function but keeps a SQRESULT for backward compatibility)
-fixed _set method in userdata delegates
-fixed some warnings
***version 3.1 stable***
-added slice range for tolower and toupper
-added startswith() and endswith() in string lib
-added SQ_EXCLUDE_DEFAULT_MEMFUNCTIONS to exclude default mem fuction from compilation
-added sq_getreleasehook
-added thread.wakeupthrow()
-added sq_pushthread
-added \u and \U escape sequence for UTF8,UTF16 or UCS4 characters
-added CMake scripts(thx Fabian Wolff)
-the escape character \x is based on sizeof(SQChar)
-fixed several warnings(thx Markus Oberhumer)
-fixed optimizer bug in compound arith oprators(+=,-= etc...)
-fixed sq_getrefvmcount() (thx Gerrit)
-fixed sq_getrefcount() when no references were added with sq_addref() (thx Gerrit)
-fixed bug in string.tointeger() (thx Domingo)
-fixed weakref comparison in 32bit builds using doubles(thx Domingo)
-fixed compiler bug(thx Peter)
-fixed some error in the documentation(thx Alexander)
-fixed some error reporting in compiler(thx Alexander)
-fixed incorrect optional semicolon after "if block"(thx Alexander)
-fixed crash bug in compiler related to compound arith operators(+=,-= etc...) (thx Jeff1)
***2015-01-10 ***
***version 3.1 RC 1***
-added new header sqconfig.h for all optional type declarations(unicode, 64bits etc..)
-added sq_setsharedforeignptr sq_getsharedforeignptr
-added sq_setsharedreleasehook sq_getsharedreleasehook
-added escape() in sqstd string library
-added __LINE__ and __FILE__ (thx mingodad)
-widechar support on gcc builds
-now boolean can be used in constants
-reduced dependencies on C runtime library
-newthread and sq_newthread() no longer reinitialize the root table on friend VMs(thx Lucas Cardellini)
-exceptions in the _inherited metamethod are propagated(thx Lucas Cardellini)
-'in' operator performance improvement(thx unagipai and mingodad)
-fixes crash in compiler when trying to write 'base'
-fixed bug in switch statement when using locals as case values (thx mingodad)
-fixed bug in print()(thx Lucas Cardellini)
***2013-08-30 ***
***version 3.1 beta 1***
-added new scoping rule(root attached to closures)
-added closure.setroot() closure.getroot()
-added sq_setclosureroot() and sq_getclosureroot()
-added sq_setvmreleasehook() and sq_getvmreleasehook()
-added documentaion for sq_getbase()
-now string.tointeger() accepts an optional parameter 'base'
-now format accepts zeroes in the format string (thx mingodad)
-fixed bug in sqstd_createfile() (thx mingodad)
-minor buxfixes
***2012-11-10 ***
***version 3.0.4 stable***
-sq_deleteslot slot now pops the key in case of failure
-fixed bug when _get metamethod throws null
-fixed a bug in rstrip
-added some error handling
-minor bugfixes
***2012-06-19 ***
***version 3.1.0 alpha 1***
-changed in and instanceof operator precendence
-root object in closures
-added closure.setroot closure.getroot
-added sq_setclosureroot and sq_getclosureroot
***version 3.0.3 stable***
-improved error messages for _cmp(when a non integer value is returned) (thx Yexo)
-added class.newmember() built in method (thx Nam)
-added class.rawnewmember() built in method (thx Nam)
-added sq_rawnewmember() (thx Nam)
-added sq_getversion()
-added sq_typeof()
-added sq_getclosurename()
-added file.close() in stdlib
-documented closure.getinfos() built-in method
-fixed string iteration doesn't return negative numbers for characters > 127
-fixed bug in tofloat() when converting a string with scientific notation without a decimal point (thx wr2)
-fixed potential infinite loop in array.sort() when the _cmp function is inconsistent (thx Yexo)
-fixed obscure bug in the compiler(thx yishin)
-fixed some minor bug
***2011-11-28 ***
***version 3.0.2 stable***
-added sq_gethash API
-now array.sort() is implemented with heapsort
-now floats in scientific notation also accept numbers with no '.' (eg. 1e+6 or 1e6)
-fixed some warning
-fixed some documentation
-fixed bug in GC
***2011-09-08 ***
***version 3.0.1 stable***
-added # as alternative symbol for "line comment"(mostly useful for shell scripts)
-added sq_throwobject() to throw an arbitrary object from the C API
-added alignement flag for userdata types, SQ_ALIGNMENT (thx Shigemasa)
-added rawset() and rawget() to class and instance default delegate
-changed bytecode format now ensures matching integer size and float size
-now inherited classes also inherit userdatasize
-added SQUIRREL_VERSION_NUMBER in squirrel.h and _versionnumber_ global symbol
-fixed sq_getmemberhandle
-fixed sq_getrefcount
-refactored some sqstdio code
-refactored some clone code
-refactored some stuff in the string lib
-added -s and -fno-exceptions in GCC makefile(better performance when using GCC)
***2011-03-13 ***
***version 3.0 stable***
-added sq_getcallee()
-sq_getfreevariable() also works for native closures
-minior optimizations
-removed several warning when compiling with GCC 4.x
-fixed some errors in the documentation
-fixed bug when using SQUSEDOUBLE and 32bits intengers
-fixed bug when invoking generators with closure.call() (thx huntercool)
***2010-12-19 ***
***version 3.0 release candidate 1(RC 1)***
-improved metamethods error handling
-added parameter 'isstatic' to _newmember metamethod(thx G.Meyer)
-added sq_getrefcount() to return number of refences from C++(thx G.Meyer)
***2010-11-07 ***
***version 3.0 beta 3***
-license changed to "MIT license"
-added sq_resurrectunreachable() and resurrectunreachable()
-added callee() built in function, returns the current running closure
-added thread.getstackinfos()
-added sq_objtouserpointer()
-added sq_newtableex()
-various refactoring and optimizations
-fixed several 64bits issues regarding integer to string conversions
-fixed some bugs when SQUSEDOUBLE is used in 32bits systems
***2010-08-18 ***
***version 3.0 beta 2.1***
-fixed bug in class constructor
-fixed bug in compound arith
***2010-08-12 ***
***version 3.0 beta 2***
-class methods can be added or replaced after the class as been instantiated
-JSON compliant table syntax, this is currently an experimental feature (thx atai)
-sq_getsize() now returns userdatasize for classes and instances
-now setroottable() and setconsttable() return the previous value of the respective table
-fixed bug in compound arith operators when used on a free variable (thx ellon)
-fixed some x64 minor bugs
-fixed minor bug in the compiler
-refactored some VM internals
-documented sq_getmemberhandle, sq_getbyhandle, sq_setbyhandle to set and get value from classes
***2009-11-15 ***
***version 3.0 beta 1***
-various refactoring and optimizations
-fixed bug in free variables (thx mokehehe)
-fixed bug in functions with default parameters (thx ara & Yexo)
-fixed bug in exception handling
-improved error propagation in _set and _get metamethods ( and 'throw null' for clean failure)
-added sq_getmemberhandle, sq_getbyhandle, sq_setbyhandle to set and get value from classes
***2009-06-30 ***
***version 3.0 alpha 2***
-added real free variables(thx Paul Ruizendaal)
-added refactored function call implementation and compiler(thx Paul Ruizendaal)
-added sq_getfunctioninfo
-added compile time flag SQUSEDOUBLE to use double precision floats
-added global slot _floatsize_ int the base lib to recognize single precision and double precision builds
-sq_wakeupvm can now resume the vm with an exception
-added sqstd_format
-now blobs can be cloned
-generators can now be instantiated by calling sq_call() or closure.call()
-fixed debughook bug
-fixed cooroutine error propagation
***2008-07-23 ***
***version 3.0 alpha 1***
-first branch from 2.x source tree
-added 'base' keyword
-removed 'delegate' keyword
-now compiled scripts are vararg functions
-added setdelegate() and getdelegate() table builtin methods
-added <=> 3 ways compare operator
-added lambda expression @(a,b) a + b
-added local function statement
-added array built-in map(),reduce(),apply(),filter() and find()
-generators hold only a weak reference of the enviroment object
-removed 'vargv' and 'vargc' keywords
-now var args are passed as an array called vargv(as a paramter)
-removed 'parent' keyword
-added class getbase() built in method
-instanceof doesn't throw an exception if the left expression is not a class
-lexical scoping for free variables(free variables are no longer in the second parameter list)
-sq_setprintfunc accept error func
-sq_geterrorfunc()
-added sq_arrayremove() and sq_arrayinsert()
-error() built in function(works like print but prints using the errorfunc)
-added native debug hook
***2008-02-17 ***
***version 2.2 stable***
-added _newslot metamethod in classes
-added enums added constants
-added sq_pushconsttable, sq_setconsttable
-added default param
-added octal literals(thx Dinosaur)
-fixed debug hook, 'calls' and 'returns' are properly notified in the same number.
-fixed a coroutine bug
***2007-07-29 ***
***version 2.1.2 stable***
-new behaviour for generators iteration using foreach
now when a generator is iterated by foreach the value returned by a 'return val' statement
will terminate the iteration but will not be returned as foreach iteration
-added sq_setclassudsize()
-added sq_clear()
-added table.clear(), array.clear()
-fixed sq_cmp() (thx jyuill)
-fixed minor bugs
***2006-08-21 ***
***version 2.1.1 stable***
-vm refactoring
-optimized internal function memory layout
-new global symbol _version_ (is the version string)
-code size optimization for float literals(on 32bits float builts)
-now the raw ref API(sq_addref etc...) is fully reentrant.
-fixed a bug in sq_getdelegate() now pushes null if the object doesn't have a delegate(thx MatzeB)
-improved C reference performances in NO_GARBAGE_COLLECTOR builds
-sq_getlocal() now enumerates also outer values.
-fixed regexp library for GCC users.
***2006-03-19 ***
***version 2.1 stable***
-added static class fields, new keyword static
-added 64bits architecture support
-added global slot _intsize_ int the base lib to recognize 32bits and 64bits builds
-added functions with fixed environment, closure.bindenv() built-in function
-all types except userdata and null implement the tostring() method
-string concatenation now invokes metamethod _tostring
-new metamethods for class objects _newmember and _inherited
-sq_call() sq_resume() sq_wakeupvm() have a new signature
-new C referencing implementation(scales more with the amount of references)
-refactored hash table
-new api functions sq_newslot(),sq_tobool(),sq_getbase(), sq_instanceof(), sq_bindenv()
-the api func sq_createslot was deprecated but still supported in form of C macro on top of sq_newslot
-sq_setreleasehook() now also works for classes
-stream.readstr() and stream.writestr() have been deprecated(this affects file and blob)
-fixed squirrel.h undeclared api calls
-fixed few minor bugs
-SQChar is now defined as wchar_t
-removed warning when building with -Wall -pedantic for GCC users
-added new std io function writeclosuretofile()
-added new std string functions strip(),rstrip(),lstrip() and split()
-regular expressions operators (+,*) now have more POSIX greedyness behaviour
-class constructors are now invoked as normal functions
***2005-10-02 ***
***version 2.0.5 stable***
-fixed some 64bits incompatibilities (thx sarge)
-fixed minor bug in the stdlib format() function (thx Rick)
-fixed a bug in dofile() that was preventing to compile empty files
-added new API sq_poptop() & sq_getfreevariable()
-some performance improvements
***2005-08-14 ***
***version 2.0.4 stable***
-weak references and related API calls
-added sq_objtobool()
-class instances memory policies improved(1 mem allocation for the whole instance)
-typetags are now declared as SQUserPointer instead of unsigned int
-first pass for 64bits compatibility
-fixed minor bug in the stdio stream
-fixed a bug in format()
-fixed bug in string.tointeger() and string.tofloat()
***2005-06-24 ***
***version 2.0.3 stable***
-dofile() and loadfile() in the iolib now can decode ASCII, UTF8 files UCS2 big-endian and little-endian
-sq_setparamscheck() : now typemesk can check for null
-added string escape sequence \xhhhh
-fixed some C++ standard incompatibilities
***2005-05-15 ***
***version 2.0.2 stable***
-performances improvements (expecially for GCC users)
-removed all dependencies from C++ exception handling
-various bugfixes
***2005-04-12 ***
***version 2.0.1 stable***
-various bugfixes
-sq_setparamscheck() now allows spaces in the typemask
***2005-04-03 ***
***version 2.0 stable***
-added API sq_gettypetag()
-added built-in function to the bool type(tointeger, tostring etc...)
***2005-02-27 ***
***version 2.0 release candidate 1(RC 1)***
-added API sq_reseterror()
-modified sq_release()
-now class instances can be cloned
-various bufixes
***2005-01-26 ***
***version 2.0 beta 1***
-added bool type
-class properties can be redefined in a derived class
-added ops *= /= and %=
-new syntax for class attributes declaration </ and /> instead of ( and )
-increased the max number of literals per function from 65535 to 16777215
-now free variables have proper lexical scoping
-added API sq_createinstance(), sq_pushbool(), sq_getbool()
-added built-in function type()
-added built-in function obj.rawin(key) in table,class and instance
-sq_rawget() and sq_rawset() now work also on classes and instances
-the VM no longer uses C++ exception handling (more suitable for embedded devices)
-various bufixes
***2004-12-21 ***
***version 2.0 alpha 2***
-globals scoping changed, now if :: is omitted the VM automatically falls back on the root table
-various bufixes
-added class level attributes
***2004-12-12 ***
***version 2.0 alpha 1***
-codebase branch from version 1.x
-added classes
-added functions with variable number of parameters(vargc & vargv and the ...)
-0 and 0.0 are now considered 'false' by all conditional statements(if,while,for,?,do-while)
-added new api functions sq_newclass() sq_setinstanceup() sq_getinstanceup() sq_getattributes() sq_setattributes()
-modified api sq_settypetag()
***2004-11-01 ***
***version 1.0 stable***
-fixed some minor bug
-improved operator 'delete' performances
-added scientific notation for float numbers( eg. 2.e16 or 2.e-2)
***2004-08-30 ***
***version 1.0 release candidate 2(RC 2)***
-fixed bug in the vm(thx Pierre Renaux)
-fixed bug in the optimizer(thx Pierre Renaux)
-fixed some bug in the documentation(thx JD)
-added new api functions for raw object handling
-removed nested multiline comments
-reduced memory footprint in C references
***2004-08-23 ***
***version 1.0 release candidate 1(RC 1)***
-fixed division by zero
-the 'in' operator and obj.rawget() do not query the default delegate anymore
-added function sq_getprintfunc()
-added new standard library 'auxlib'(implements default error handlers)
***2004-07-12 ***
***version 1.0 beta 4***
-fixed a bug in the integer.tochar() built-in method
-fixed unary minus operator
-fixed bug in dofile()
-fixed inconsistency between != and == operators(on float/integer comparison)
-added javascript style unsigned right shift operator '>>>'
-added array(size) constructor built-in function
-array.resize(size,[fill]) built-in function accepts an optional 'fill' value
-improved debug API, added sq_getclosureinfo() and sq_setnativeclosurename()
***2004-05-23 ***
***version 1.0 beta 3***
-minor vm bug fixes
-string allocation is now faster
-tables and array memory usage is now less conservative(they shrink)
-added regular expression routines in the standard library
-The 'c' expression now accepts only 1 character(thx irbrian)
-multiline strings <[ ]> have been substituted with C# style verbatim strings (eg. @"string")
-added new keyword 'parent' for accessing the delegate of tables and unserdata
-The metamethod '_clone' has been renamed '_cloned'
-the _delslot metamethod's behaviour and prototype have been changed
-new default function in the integer and float object 'tochar()'
-the built-in function chcode2string has been removed
-the default method [table].getdelegate() has been removed
-new api sq_rawdeleteslot()
-new table built-in method rawdelete(key)
-the dynamic mudule loading has been removed from the standard distribution
-some optimizations in the VM
***2004-04-21 ***
***version 1.0 beta 2***
-minor compiler/parser bug fixes
-sq_newclosure has a different prototype, the "paramscheck" of paramter has been moved to the new function sq_setparamscheck()
-sq_setparamscheck allows to add automatic parameters type checking in native closures
-sq_compile() lost the lineinfo parameter
-new api sq_enabledebuginfo() globally sets compiler's debug info generation
-added consistency check on bytecode serialization
-fixed += operator, now works on strings like +
-added global slot in the base lib _charsize_ to recognize unicode builds from ascii builds runtime
-added registry table
-new api call sq_pushregistrytable()
-added type tag to the userdata type sq_settypetag()
-sq_getuserdata now queries the userdata typetag
-the built in function collect_garbage() as been renamed collectgarbage() for consistency reasons
-new standard libraries(sqlibs are now obsolete)
***2004-02-20 ***
***version 1.0 beta 1***
-fixed a bug in the compiler (thanks Martin Kofler)
-fixed bug in the switch case statement
-fixed the _unm metamethod
-fixed minor bugs in the API
-fixed automatic stack resizing
-first beta version
first pass code clean up in the VM and base lib
first pass code coverege test has been done on VM and built-in lib
-new VM creation API sq_open() sq_close() (sq_newvm and sq_releasevm are now obsolete)
-new api allows to specifiy a "print" function to output text(sq_printfunc)
-added some small optimizations
-new cooperative multi-threading capabilities in the base library(coroutines), VMs are now a built in type("thread")
-new built in functions have been added for manipulating the new "thread" type
-friend virtual machines share the same root table, error handler and debug hook by default
-new compile time options
***2004-01-19 ***
***version 0.9 alpha***
-fixed a garbage collection bug
-fixed some API bugs(thanks to Joshua Jensen)
-fixed tail calls (in the version 0.8 the tail call optimization was erroneously disabled)
-new function parameters semantic, now passing a wrong number of parameters generates an exception
-native closures have now a built in parameter number checking
-sq_rawget and sq_rawset now work also on arrays
-sq_getsize now woks also on userdata
-the userdata release hook prototype is changed(now passes the size of the userdata)
-the lexer reader function now returns an integer instead of a char that allows better error checking on the input(thx Joshua Jensen)
-faster compiler
-try/catch blocks do not cause any runtime memory allocation anymore
***2003-12-06 ***
***version 0.8 alpha***
-fixed a bug that was preventing to have callable userdata throught the metamethod _call
-fixed a garbage collection bug
-fixed == operator now can compare correctly different types
-new built in method getstackinfos(level)
-improved line informations precision for the debug hook
-new api call sq_compilebuffer()
-new built-in api function compilestring()
-new syntactic sugar for function declarations inside tables
-the debug API has been finalized
***2003-11-17 ***
***version 0.7 alpha***
-fixed critical bug SQInteger the tail call system
-fixed bug in the continue statement code generation
-fixed func call param issue(thanks to Rewoonenco Andrew)
-added _delslot metamethod(thanks to Rewoonenco Andrew)
-new multiline string expression ( delimited by <[ and ]> )
-normal strings ("") do not allow embedded new line anymore
-reduced vm memory footprint(C refs are shared between friend VMs)
-new api method sq_deleteslot()
-new debug hook event 'r' is triggered when a function returns
***2003-11-04 ***
***version 0.6 alpha***
-fixed switch statement(was executing the default case after a break)
-sq_call() doesn't pop the closure (just the params)
-the vm execution can be suspended from the C API anytime (micro-threads)
-new api calls sq_suspendvm() sq_wakeupvm() sq_getvmstate() and sq_reservestack()
***2003-10-13 ***
***version 0.5 alpha***
-fixed some minor bug
-tested with non ASCII identifiers in unicode mode(I've tried chinese chars)
-added built-in function string.find()
-the built-in function array.sort() optionally accepts a cmp(a,b) function
-the debug hook function now has a new prototype debug_hook(event_type,sourcefile,line,functionname)
-fixed some debug info imprecision
***2003-10-01 ***
***version 0.4 alpha***
-faster VM
-sq_call will pop arguments and closure also in case of failure
-fixed a bug in sq_remove
-now the VM detects delegation cycles(and throws an exception)
-new operators ++ and --
-new operator ',' comma operator
-fixed some expression precedence issue
-fixed bug in sq_arraypop
***2003-09-15 ***
***version 0.3 alpha***
-fixed a bug in array::insert()
-optional Unicode core(define SQUNICODE or _UNICODE on Win32)
-sq_compiler uses a new reader function SQLEXREADFUNC
-the debug hook passes 'l' instead of 'line' for line callbacks
and 'c' instead of 'call' for call callbacks
-new array.extend() bulit-in function
-new API sq_clone()
***2003-09-10 ***
***version 0.2 pre-alpha***
-new completely reentrant VM (sq_open and sq_close are now obsolete)
-sq_newvm() has a new prototype
-allocators are now global and linked in the VM
-_newslot meta method added
-rawset creates a slot if doesn't exists
-the compiler error callback pass the vm handle(thanks Pierre Renaux)
-sq_setforeignptr() sq_getforeingptr() are now public
-sq_resume() now is possible to resume generators from C
-sq_getlasterror() retrieve the last thrown error
-improved docs
***2003-09-06 ***
***version 0.1 pre-alpha***
first release

View File

@ -0,0 +1,22 @@
SQUIRREL=.
MAKE=make
sq32: folders
cd squirrel; $(MAKE)
cd sqstdlib; $(MAKE)
cd sq; $(MAKE)
sqprof: folders
cd squirrel; $(MAKE) sqprof
cd sqstdlib; $(MAKE) sqprof
cd sq; $(MAKE) sqprof
sq64: folders
cd squirrel; $(MAKE) sq64
cd sqstdlib; $(MAKE) sq64
cd sq; $(MAKE) sq64
folders:
mkdir -p lib
mkdir -p bin

View File

@ -0,0 +1,33 @@
The programming language SQUIRREL 3.1 stable
--------------------------------------------------
This project has successfully been compiled and run on
* Windows (x86 and amd64)
* Linux (x86, amd64 and ARM)
* Illumos (x86 and amd64)
* FreeBSD (x86 and ARM)
The following compilers have been confirmed to be working:
MS Visual C++ 6.0 (all on x86 and amd64)
7.0 |
7.1 v
8.0
9.0
10.0
12.0 ---
MinGW gcc 3.2 (mingw special 20020817-1)
Cygnus gcc 3.2
Linux gcc 3.2.3
4.0.0 (x86 and amd64)
5.3.1 (amd64)
Illumos gcc 4.0.0 (x86 and amd64)
ARM Linux gcc 4.6.3 (Raspberry Pi Model B)
Feedback and suggestions are appreciated
project page - http://www.squirrel-lang.org
community forums - http://forum.squirrel-lang.org
wiki - http://wiki.squirrel-lang.org
author - alberto@demichelis.net
END OF README

View File

@ -0,0 +1,28 @@
version: 0.0.{build}
platform:
- x86
- x64
configuration:
- Debug
- Release
clone_folder: c:\sq
before_build:
- mkdir build
- cd build
- call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %platform%
- echo %platform%
- if %platform%==X64 (cmake .. -G "Visual Studio 14 2015 Win64")
- if %platform%==x86 (cmake .. -G "Visual Studio 14 2015")
build_script:
- cmake --build . --config %configuration% -- /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
artifacts:
- path: build\*\%configuration%\*.exe
- path: build\*\%configuration%\*.dll
test: off

View File

@ -0,0 +1,216 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = build
# User-friendly check for sphinx-build
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
endif
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
.PHONY: help
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " applehelp to make an Apple Help Book"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " xml to make Docutils-native XML files"
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
@echo " coverage to run coverage check of the documentation (if enabled)"
.PHONY: clean
clean:
rm -rf $(BUILDDIR)/*
.PHONY: html
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
.PHONY: dirhtml
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
.PHONY: singlehtml
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
.PHONY: pickle
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
.PHONY: json
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
.PHONY: htmlhelp
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
.PHONY: qthelp
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/testy_sphinxy.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/testy_sphinxy.qhc"
.PHONY: applehelp
applehelp:
$(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
@echo
@echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
@echo "N.B. You won't be able to view it unless you put it in" \
"~/Library/Documentation/Help or install it in your application" \
"bundle."
.PHONY: devhelp
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/testy_sphinxy"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/testy_sphinxy"
@echo "# devhelp"
.PHONY: epub
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
.PHONY: latex
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
.PHONY: latexpdf
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
.PHONY: latexpdfja
latexpdfja:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through platex and dvipdfmx..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
.PHONY: text
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
.PHONY: man
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
.PHONY: texinfo
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
.PHONY: info
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
.PHONY: gettext
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
.PHONY: changes
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
.PHONY: linkcheck
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
.PHONY: doctest
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."
.PHONY: coverage
coverage:
$(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
@echo "Testing of coverage in the sources finished, look at the " \
"results in $(BUILDDIR)/coverage/python.txt."
.PHONY: xml
xml:
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
@echo
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
.PHONY: pseudoxml
pseudoxml:
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
@echo
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."

View File

@ -0,0 +1,263 @@
@ECHO OFF
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set BUILDDIR=build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source
set I18NSPHINXOPTS=%SPHINXOPTS% source
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^<target^>` where ^<target^> is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. singlehtml to make a single large HTML file
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. devhelp to make HTML files and a Devhelp project
echo. epub to make an epub
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. text to make text files
echo. man to make manual pages
echo. texinfo to make Texinfo files
echo. gettext to make PO message catalogs
echo. changes to make an overview over all changed/added/deprecated items
echo. xml to make Docutils-native XML files
echo. pseudoxml to make pseudoxml-XML files for display purposes
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
echo. coverage to run coverage check of the documentation if enabled
goto end
)
if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\*
goto end
)
REM Check if sphinx-build is available and fallback to Python version if any
%SPHINXBUILD% 1>NUL 2>NUL
if errorlevel 9009 goto sphinx_python
goto sphinx_ok
:sphinx_python
set SPHINXBUILD=python -m sphinx.__init__
%SPHINXBUILD% 2> nul
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
:sphinx_ok
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "singlehtml" (
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\testy_sphinxy.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\testy_sphinxy.ghc
goto end
)
if "%1" == "devhelp" (
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished.
goto end
)
if "%1" == "epub" (
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The epub file is in %BUILDDIR%/epub.
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
if errorlevel 1 exit /b 1
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "latexpdf" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
cd %BUILDDIR%/latex
make all-pdf
cd %~dp0
echo.
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "latexpdfja" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
cd %BUILDDIR%/latex
make all-pdf-ja
cd %~dp0
echo.
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "text" (
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The text files are in %BUILDDIR%/text.
goto end
)
if "%1" == "man" (
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The manual pages are in %BUILDDIR%/man.
goto end
)
if "%1" == "texinfo" (
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
goto end
)
if "%1" == "gettext" (
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
if errorlevel 1 exit /b 1
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
if errorlevel 1 exit /b 1
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
if errorlevel 1 exit /b 1
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
if "%1" == "coverage" (
%SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage
if errorlevel 1 exit /b 1
echo.
echo.Testing of coverage in the sources finished, look at the ^
results in %BUILDDIR%/coverage/python.txt.
goto end
)
if "%1" == "xml" (
%SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The XML files are in %BUILDDIR%/xml.
goto end
)
if "%1" == "pseudoxml" (
%SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
goto end
)
:end

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 393 B

View File

@ -0,0 +1,288 @@
# -*- coding: utf-8 -*-
#
# Squirrel documentation build configuration file, created by
# sphinx-quickstart on Sun Jan 31 00:26:52 2016.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys
import os
import time
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'Squirrel documentation'
copyright = '2003-%s, Alberto Demichelis' % time.strftime('%Y')
author = u'Alberto Demichelis'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = u'3.1'
# The full version, including alpha/beta/rc tags.
release = u'3.1 stable'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = []
# The reST default role (used for this markup: `text`) to use for all
# documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents.
#keep_warnings = False
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'sphinx_rtd_theme'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
html_logo = 'simple_nut.png'
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
html_favicon = 'nut.ico'
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
#html_extra_path = []
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Language to be used for generating the HTML full-text search index.
# Sphinx supports the following languages:
# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr'
#html_search_language = 'en'
# A dictionary with options for the search language support, empty by default.
# Now only 'ja' uses this config value
#html_search_options = {'type': 'default'}
# The name of a javascript file (relative to the configuration directory) that
# implements a search results scorer. If empty, the default will be used.
#html_search_scorer = 'scorer.js'
# Output file base name for HTML help builder.
htmlhelp_basename = 'squirrel_doc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
# Latex figure (float) alignment
#'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
_stdauthor = r'Alberto Demichelis'
latex_documents = [
('reference/index', 'reference.tex',
'Squirrel Reference Manual', _stdauthor, 'manual'),
('stdlib/index', 'stdlib.tex',
'Squirrel Standard Library', _stdauthor, 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'Squirrel', u'Squirrel Documentation',
[author], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'Squirrel', u'Squirrel Documentation',
author, 'Squirrel', 'The Programming Language.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False

View File

@ -0,0 +1,24 @@
.. Squirrel documentation master file, created by
sphinx-quickstart on Sun Jan 31 00:26:52 2016.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Squirrel's documentation
=========================================
Contents:
.. toctree::
:maxdepth: 1
reference/index.rst
stdlib/index.rst
Indices and tables
==================
* :ref:`genindex`
* :ref:`search`

View File

@ -0,0 +1,32 @@
.. _api_ref_bytecode_serialization:
======================
Bytecode serialization
======================
.. _sq_readclosure:
.. c:function:: SQRESULT sq_readclosure(HSQUIRRELVM v, SQREADFUNC readf, SQUserPointer up)
:param HSQUIRRELVM v: the target VM
:param SQREADFUNC readf: pointer to a read function that will be invoked by the vm during the serialization.
:param SQUserPointer up: pointer that will be passed to each call to the read function
:returns: a SQRESULT
serialize (read) a closure and pushes it on top of the stack, the source is user defined through a read callback.
.. _sq_writeclosure:
.. c:function:: SQRESULT sq_writeclosure(HSQUIRRELVM v, SQWRITEFUNC writef, SQUserPointer up)
:param HSQUIRRELVM v: the target VM
:param SQWRITEFUNC writef: pointer to a write function that will be invoked by the vm during the serialization.
:param SQUserPointer up: pointer that will be passed to each call to the write function
:returns: a SQRESULT
:remarks: closures with free variables cannot be serialized
serializes(writes) the closure on top of the stack, the destination is user defined through a write callback.

View File

@ -0,0 +1,130 @@
.. _api_ref_calls:
=====
Calls
=====
.. _sq_call:
.. c:function:: SQRESULT sq_call(HSQUIRRELVM v, SQInteger params, SQBool retval, SQBool raiseerror)
:param HSQUIRRELVM v: the target VM
:param SQInteger params: number of parameters of the function
:param SQBool retval: if true the function will push the return value in the stack
:param SQBool raiseerror: if true, if a runtime error occurs during the execution of the call, the vm will invoke the error handler.
:returns: a SQRESULT
calls a closure or a native closure. The function pops all the parameters and leave the closure in the stack; if retval is true the return value of the closure is pushed. If the execution of the function is suspended through sq_suspendvm(), the closure and the arguments will not be automatically popped from the stack.
When using to create an instance, push a dummy parameter to be filled with the newly-created instance for the constructor's 'this' parameter.
.. _sq_getcallee:
.. c:function:: SQRESULT sq_getcallee(HSQUIRRELVM v)
:param HSQUIRRELVM v: the target VM
:returns: a SQRESULT
push in the stack the currently running closure.
.. _sq_getlasterror:
.. c:function:: SQRESULT sq_getlasterror(HSQUIRRELVM v)
:param HSQUIRRELVM v: the target VM
:returns: a SQRESULT
:remarks: the pushed error descriptor can be any valid squirrel type.
pushes the last error in the stack.
.. _sq_getlocal:
.. c:function:: const SQChar * sq_getlocal(HSQUIRRELVM v, SQUnsignedInteger level, SQUnsignedInteger nseq)
:param HSQUIRRELVM v: the target VM
:param SQUnsignedInteger level: the function index in the calls stack, 0 is the current function
:param SQUnsignedInteger nseq: the index of the local variable in the stack frame (0 is 'this')
:returns: the name of the local variable if a variable exists at the given level/seq otherwise NULL.
Returns the name of a local variable given stackframe and sequence in the stack and pushes is current value. Free variables are treated as local variables, by sq_getlocal(), and will be returned as they would be at the base of the stack, just before the real local variables.
.. _sq_reseterror:
.. c:function:: void sq_reseterror(HSQUIRRELVM v)
:param HSQUIRRELVM v: the target VM
reset the last error in the virtual machine to null
.. _sq_resume:
.. c:function:: SQRESULT sq_resume(HSQUIRRELVM v, SQBool retval, SQBool raiseerror)
:param HSQUIRRELVM v: the target VM
:param SQBool retval: if true the function will push the return value in the stack
:param SQBool raiseerror: if true, if a runtime error occurs during the execution of the call, the vm will invoke the error handler.
:returns: a SQRESULT
:remarks: if retval != 0 the return value of the generator is pushed.
resumes the generator at the top position of the stack.
.. _sq_tailcall:
.. c:function:: SQRESULT sq_tailcall(HSQUIRRELVM v, SQInteger nparams)
:param HSQUIRRELVM v: the target VM
:param SQInteger params: number of parameters of the function
Calls a closure and removes the caller function from the call stack.
This function must be invoke from a native closure and
he return value of sq_tailcall must be returned by the caller function(see example).
*.eg*
::
SQInteger tailcall_something_example(HSQUIRRELVM v)
{
//push closure and parameters here
...
return sq_tailcall(v,2);
}
.. _sq_throwerror:
.. c:function:: SQRESULT sq_throwerror(HSQUIRRELVM v, const SQChar * err)
:param HSQUIRRELVM v: the target VM
:param const SQChar * err: the description of the error that has to be thrown
:returns: the value that has to be returned by a native closure in order to throw an exception in the virtual machine.
sets the last error in the virtual machine and returns the value that has to be returned by a native closure in order to trigger an exception in the virtual machine.
.. _sq_throwobject:
.. c:function:: SQRESULT sq_throwobject(HSQUIRRELVM v)
:param HSQUIRRELVM v: the target VM
:returns: the value that has to be returned by a native closure in order to throw an exception in the virtual machine.
pops a value from the stack sets it as the last error in the virtual machine. Returns the value that has to be returned by a native closure in order to trigger an exception in the virtual machine (aka SQ_ERROR).

View File

@ -0,0 +1,79 @@
.. _api_ref_compiler:
========
Compiler
========
.. _sq_compile:
.. c:function:: SQRESULT sq_compile(HSQUIRRELVM v, HSQLEXREADFUNC read, SQUserPointer p, const SQChar * sourcename, SQBool raiseerror)
:param HSQUIRRELVM v: the target VM
:param HSQLEXREADFUNC read: a pointer to a read function that will feed the compiler with the program.
:param SQUserPointer p: a user defined pointer that will be passed by the compiler to the read function at each invocation.
:param const SQChar * sourcename: the symbolic name of the program (used only for more meaningful runtime errors)
:param SQBool raiseerror: if this value is true the compiler error handler will be called in case of an error
:returns: a SQRESULT. If the sq_compile fails nothing is pushed in the stack.
:remarks: in case of an error the function will call the function set by sq_setcompilererrorhandler().
compiles a squirrel program; if it succeeds, push the compiled script as function in the stack.
.. _sq_compilebuffer:
.. c:function:: SQRESULT sq_compilebuffer(HSQUIRRELVM v, const SQChar* s, SQInteger size, const SQChar * sourcename, SQBool raiseerror)
:param HSQUIRRELVM v: the target VM
:param const SQChar* s: a pointer to the buffer that has to be compiled.
:param SQInteger size: size in characters of the buffer passed in the parameter 's'.
:param const SQChar * sourcename: the symbolic name of the program (used only for more meaningful runtime errors)
:param SQBool raiseerror: if this value true the compiler error handler will be called in case of an error
:returns: a SQRESULT. If the sq_compilebuffer fails nothing is pushed in the stack.
:remarks: in case of an error the function will call the function set by sq_setcompilererrorhandler().
compiles a squirrel program from a memory buffer; if it succeeds, push the compiled script as function in the stack.
.. _sq_enabledebuginfo:
.. c:function:: void sq_enabledebuginfo(HSQUIRRELVM v, SQBool enable)
:param HSQUIRRELVM v: the target VM
:param SQBool enable: if true enables the debug info generation, if == 0 disables it.
:remarks: The function affects all threads as well.
enable/disable the debug line information generation at compile time.
.. _sq_notifyallexceptions:
.. c:function:: void sq_notifyallexceptions(HSQUIRRELVM v, SQBool enable)
:param HSQUIRRELVM v: the target VM
:param SQBool enable: if true enables the error callback notification of handled exceptions.
:remarks: By default the VM will invoke the error callback only if an exception is not handled (no try/catch traps are present in the call stack). If notifyallexceptions is enabled, the VM will call the error callback for any exception even if between try/catch blocks. This feature is useful for implementing debuggers.
enable/disable the error callback notification of handled exceptions.
.. _sq_setcompilererrorhandler:
.. c:function:: void sq_setcompilererrorhandler(HSQUIRRELVM v, SQCOMPILERERROR f)
:param HSQUIRRELVM v: the target VM
:param SQCOMPILERERROR f: A pointer to the error handler function
:remarks: if the parameter f is NULL no function will be called when a compiler error occurs. The compiler error handler is shared between friend VMs.
sets the compiler error handler function

View File

@ -0,0 +1,72 @@
.. _api_ref_debug_interface:
===============
Debug interface
===============
.. _sq_getfunctioninfo:
.. c:function:: SQRESULT sq_getfunctioninfo(HSQUIRRELVM v, SQInteger level, SQFunctionInfo * fi)
:param HSQUIRRELVM v: the target VM
:param SQInteger level: calls stack level
:param SQFunctionInfo * fi: pointer to the SQFunctionInfo structure that will store the closure informations
:returns: a SQRESULT.
:remarks: the member 'funcid' of the returned SQFunctionInfo structure is a unique identifier of the function; this can be useful to identify a specific piece of squirrel code in an application like for instance a profiler. this method will fail if the closure in the stack is a native C closure.
*.eg*
::
typedef struct tagSQFunctionInfo {
SQUserPointer funcid; //unique idetifier for a function (all it's closures will share the same funcid)
const SQChar *name; //function name
const SQChar *source; //function source file name
}SQFunctionInfo;
.. _sq_setdebughook:
.. c:function:: void sq_setdebughook(HSQUIRRELVM v)
:param HSQUIRRELVM v: the target VM
:remarks: In order to receive a 'per line' callback, is necessary to compile the scripts with the line informations. Without line informations activated, only the 'call/return' callbacks will be invoked.
pops a closure from the stack an sets it as debug hook. When a debug hook is set it overrides any previously set native or non native hooks. if the hook is null the debug hook will be disabled.
.. _sq_setnativedebughook:
.. c:function:: void sq_setnativedebughook(HSQUIRRELVM v, SQDEBUGHOOK hook)
:param HSQUIRRELVM v: the target VM
:param SQDEBUGHOOK hook: the native hook function
:remarks: In order to receive a 'per line' callback, is necessary to compile the scripts with the line informations. Without line informations activated, only the 'call/return' callbacks will be invoked.
sets the native debug hook. When a native hook is set it overrides any previously set native or non native hooks. if the hook is NULL the debug hook will be disabled.
.. _sq_stackinfos:
.. c:function:: SQRESULT sq_stackinfos(HSQUIRRELVM v, SQInteger level, SQStackInfos * si)
:param HSQUIRRELVM v: the target VM
:param SQInteger level: calls stack level
:param SQStackInfos * si: pointer to the SQStackInfos structure that will store the stack informations
:returns: a SQRESULT.
retrieve the calls stack informations of a ceratain level in the calls stack.

View File

@ -0,0 +1,27 @@
.. _api_ref_garbage_collector:
=================
Garbage Collector
=================
.. _sq_collectgarbage:
.. c:function:: SQInteger sq_collectgarbage(HSQUIRRELVM v)
:param HSQUIRRELVM v: the target VM
:remarks: this api only works with garbage collector builds (NO_GARBAGE_COLLECTOR is not defined)
runs the garbage collector and returns the number of reference cycles found (and deleted)
.. _sq_resurrectunreachable:
.. c:function:: SQRESULT sq_resurrectunreachable(HSQUIRRELVM v)
:param HSQUIRRELVM v: the target VM
:remarks: this api only works with garbage collector builds (NO_GARBAGE_COLLECTOR is not defined)
runs the garbage collector and pushes an array in the stack containing all unreachable object found. If no unreachable object is found, null is pushed instead. This function is meant to help debug reference cycles.

View File

@ -0,0 +1,695 @@
.. _api_ref_object_creation_and_handling:
============================
Object creation and handling
============================
.. _sq_bindenv:
.. c:function:: SQRESULT sq_bindenv(HSQUIRRELVM v, SQInteger idx)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: index of the target closure
:returns: a SQRESULT
:remarks: the cloned closure holds the environment object as weak reference
pops an object from the stack (must be a table, instance, or class); clones the closure at position idx in the stack and sets the popped object as environment of the cloned closure. Then pushes the new cloned closure on top of the stack.
.. _sq_createinstance:
.. c:function:: SQRESULT sq_createinstance(HSQUIRRELVM v, SQInteger idx)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: index of the target class
:returns: a SQRESULT
:remarks: the function doesn't invoke the instance contructor. To create an instance and automatically invoke its contructor, sq_call must be used instead.
creates an instance of the class at 'idx' position in the stack. The new class instance is pushed on top of the stack.
.. _sq_getbool:
.. c:function:: SQRESULT sq_getbool(HSQUIRRELVM v, SQInteger idx, SQBool * b)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: an index in the stack
:param SQBool * b: A pointer to the bool that will store the value
:returns: a SQRESULT
gets the value of the bool at the idx position in the stack.
.. _sq_getbyhandle:
.. c:function:: SQRESULT sq_getbyhandle(HSQUIRRELVM v, SQInteger idx, HSQMEMBERHANDLE* handle)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: an index in the stack pointing to the class or instance
:param HSQMEMBERHANDLE* handle: a pointer to the member handle
:returns: a SQRESULT
pushes the value of a class or instance member using a member handle (see sq_getmemberhandle)
.. _sq_getclosureinfo:
.. c:function:: SQRESULT sq_getclosureinfo(HSQUIRRELVM v, SQInteger idx, SQInteger * nparams, SQInteger * nfreevars)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: index of the target closure
:param SQInteger * nparams: a pointer to an integer that will store the number of parameters
:param SQInteger * nfreevars: a pointer to an integer that will store the number of free variables
:returns: an SQRESULT
retrieves number of parameters and number of freevariables from a squirrel closure.
.. _sq_getclosurename:
.. c:function:: SQRESULT sq_getclosurename(HSQUIRRELVM v, SQInteger idx)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: index of the target closure
:returns: an SQRESULT
pushes the name of the closure at position idx in the stack. Note that the name can be a string or null if the closure is anonymous or a native closure with no name assigned to it.
.. _sq_getclosureroot:
.. c:function:: SQRESULT sq_getclosureroot(HSQUIRRELVM v, SQInteger idx)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: index of the target closure
:returns: an SQRESULT
pushes the root table of the closure at position idx in the stack
.. _sq_getfloat:
.. c:function:: SQRESULT sq_getfloat(HSQUIRRELVM v, SQInteger idx, SQFloat * f)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: an index in the stack
:param SQFloat * f: A pointer to the float that will store the value
:returns: a SQRESULT
gets the value of the float at the idx position in the stack.
.. _sq_gethash:
.. c:function:: SQHash sq_gethash(HSQUIRRELVM v, SQInteger idx)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: an index in the stack
:returns: the hash key of the value at the position idx in the stack
:remarks: the hash value function is the same used by the VM.
returns the hash key of a value at the idx position in the stack.
.. _sq_getinstanceup:
.. c:function:: SQRESULT sq_getinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer * up, SQUSerPointer typetag)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: an index in the stack
:param SQUserPointer * up: a pointer to the userpointer that will store the result
:param SQUSerPointer typetag: the typetag that has to be checked, if this value is set to 0 the typetag is ignored.
:returns: a SQRESULT
gets the userpointer of the class instance at position idx in the stack. if the parameter 'typetag' is different than 0, the function checks that the class or a base class of the instance is tagged with the specified tag; if not the function fails. If 'typetag' is 0 the function will ignore the tag check.
.. _sq_getinteger:
.. c:function:: SQRESULT sq_getinteger(HSQUIRRELVM v, SQInteger idx, SQInteger * i)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: an index in the stack
:param SQInteger * i: A pointer to the integer that will store the value
:returns: a SQRESULT
gets the value of the integer at the idx position in the stack.
.. _sq_getmemberhandle:
.. c:function:: SQRESULT sq_getmemberhandle(HSQUIRRELVM v, SQInteger idx, HSQMEMBERHANDLE* handle)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: an index in the stack pointing to the class
:param HSQMEMBERHANDLE* handle: a pointer to the variable that will store the handle
:returns: a SQRESULT
:remarks: This method works only with classes. A handle retrieved through a class can be later used to set or get values from one of the class instances. Handles retrieved from base classes are still valid in derived classes and respect inheritance rules.
pops a value from the stack and uses it as index to fetch the handle of a class member. The handle can be later used to set or get the member value using sq_getbyhandle(), sq_setbyhandle().
.. _sq_getreleasehook:
.. c:function:: SQRELEASEHOOK sq_getreleasehook(HSQUIRRELVM v, SQInteger idx)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: an index in the stack
:remarks: if the object that position idx is not an userdata, class instance or class the function returns NULL.
gets the release hook of the userdata, class instance or class at position idx in the stack.
.. _sq_getscratchpad:
.. c:function:: SQChar * sq_getscratchpad(HSQUIRRELVM v, SQInteger minsize)
:param HSQUIRRELVM v: the target VM
:param SQInteger minsize: the requested size for the scratchpad buffer
:remarks: the buffer is valid until the next call to sq_getscratchpad
returns a pointer to a memory buffer that is at least as big as minsize.
.. _sq_getsize:
.. c:function:: SQObjectType sq_getsize(HSQUIRRELVM v, SQInteger idx)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: an index in the stack
:returns: the size of the value at the position idx in the stack
:remarks: this function only works with strings, arrays, tables, classes, instances, and userdata if the value is not a valid type, the function will return -1.
returns the size of a value at the idx position in the stack. If the value is a class or a class instance the size returned is the size of the userdata buffer (see sq_setclassudsize).
.. _sq_getstring:
.. c:function:: SQRESULT sq_getstring(HSQUIRRELVM v, SQInteger idx, const SQChar ** c)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: an index in the stack
:param const SQChar ** c: a pointer to the pointer that will point to the string
:returns: a SQRESULT
gets a pointer to the string at the idx position in the stack.
.. _sq_getstringandsize:
.. c:function:: SQRESULT sq_getstringandsize(HSQUIRRELVM v, SQInteger idx, const SQChar ** c, SQInteger* size)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: an index in the stack
:param const SQChar ** c: a pointer to the pointer that will point to the string
:param SQInteger * size: a pointer to a SQInteger which will receive the size of the string
:returns: a SQRESULT
gets a pointer to the string at the idx position in the stack; additionally retrieves its size.
.. _sq_getthread:
.. c:function:: SQRESULT sq_getthread(HSQUIRRELVM v, SQInteger idx, HSQUIRRELVM* v)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: an index in the stack
:param HSQUIRRELVM* v: A pointer to the variable that will store the thread pointer
:returns: a SQRESULT
gets a pointer to the thread the idx position in the stack.
.. _sq_gettype:
.. c:function:: SQObjectType sq_gettype(HSQUIRRELVM v, SQInteger idx)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: an index in the stack
:returns: the type of the value at the position idx in the stack
returns the type of the value at the position idx in the stack
.. _sq_gettypetag:
.. c:function:: SQRESULT sq_gettypetag(HSQUIRRELVM v, SQInteger idx, SQUserPointer * typetag)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: an index in the stack
:param SQUserPointer * typetag: a pointer to the variable that will store the tag
:returns: a SQRESULT
:remarks: the function works also with instances. if the taget object is an instance, the typetag of it's base class is fetched.
gets the typetag of the object (userdata or class) at position idx in the stack.
.. _sq_getuserdata:
.. c:function:: SQRESULT sq_getuserdata(HSQUIRRELVM v, SQInteger idx, SQUserPointer * p, SQUserPointer * typetag)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: an index in the stack
:param SQUserPointer * p: A pointer to the userpointer that will point to the userdata's payload
:param SQUserPointer * typetag: A pointer to a SQUserPointer that will store the userdata tag(see sq_settypetag). The parameter can be NULL.
:returns: a SQRESULT
gets a pointer to the value of the userdata at the idx position in the stack.
.. _sq_getuserpointer:
.. c:function:: SQRESULT sq_getuserpointer(HSQUIRRELVM v, SQInteger idx, SQUserPointer * p)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: an index in the stack
:param SQUserPointer * p: A pointer to the userpointer that will store the value
:returns: a SQRESULT
gets the value of the userpointer at the idx position in the stack.
.. _sq_newarray:
.. c:function:: void sq_newarray(HSQUIRRELVM v, SQInteger size)
:param HSQUIRRELVM v: the target VM
:param SQInteger size: the size of the array that as to be created
creates a new array and pushes it in the stack
.. _sq_newclass:
.. c:function:: SQRESULT sq_newclass(HSQUIRRELVM v, SQBool hasbase)
:param HSQUIRRELVM v: the target VM
:param SQBool hasbase: if the parameter is true the function expects a base class on top of the stack.
:returns: a SQRESULT
creates a new class object. If the parameter 'hasbase' is different than 0, the function pops a class from the stack and inherits the new created class from it. The new class is pushed in the stack.
.. _sq_newclosure:
.. c:function:: void sq_newclosure(HSQUIRRELVM v, HSQFUNCTION func, SQInteger nfreevars)
:param HSQUIRRELVM v: the target VM
:param HSQFUNCTION func: a pointer to a native-function
:param SQInteger nfreevars: number of free variables(can be 0)
create a new native closure, pops n values set those as free variables of the new closure, and push the new closure in the stack.
.. _sq_newtable:
.. c:function:: void sq_newtable(HSQUIRRELVM v)
:param HSQUIRRELVM v: the target VM
creates a new table and pushes it in the stack
.. _sq_newtableex:
.. c:function:: void sq_newtableex(HSQUIRRELVM v, SQInteger initialcapacity)
:param HSQUIRRELVM v: the target VM
:param SQInteger initialcapacity: number of key/value pairs to preallocate
creates a new table and pushes it in the stack. This function allows you to specify the initial capacity of the table to prevent unnecessary rehashing when the number of slots required is known at creation-time.
.. _sq_newuserdata:
.. c:function:: SQUserPointer sq_newuserdata(HSQUIRRELVM v, SQUnsignedInteger size)
:param HSQUIRRELVM v: the target VM
:param SQUnsignedInteger size: the size of the userdata that as to be created in bytes
creates a new userdata and pushes it in the stack
.. _sq_pushbool:
.. c:function:: void sq_pushbool(HSQUIRRELVM v, SQBool b)
:param HSQUIRRELVM v: the target VM
:param SQBool b: the bool that has to be pushed(SQTrue or SQFalse)
pushes a bool into the stack
.. _sq_pushfloat:
.. c:function:: void sq_pushfloat(HSQUIRRELVM v, SQFloat f)
:param HSQUIRRELVM v: the target VM
:param SQFloat f: the float that has to be pushed
pushes a float into the stack
.. _sq_pushinteger:
.. c:function:: void sq_pushinteger(HSQUIRRELVM v, SQInteger n)
:param HSQUIRRELVM v: the target VM
:param SQInteger n: the integer that has to be pushed
pushes an integer into the stack
.. _sq_pushnull:
.. c:function:: void sq_pushnull(HSQUIRRELVM v)
:param HSQUIRRELVM v: the target VM
pushes a null value into the stack
.. _sq_pushstring:
.. c:function:: void sq_pushstring(HSQUIRRELVM v, const SQChar * s, SQInteger len)
:param HSQUIRRELVM v: the target VM
:param const SQChar * s: pointer to the string that has to be pushed
:param SQInteger len: length of the string pointed by s
:remarks: if the parameter len is less than 0 the VM will calculate the length using strlen(s)
pushes a string in the stack
.. _sq_pushuserpointer:
.. c:function:: void sq_pushuserpointer(HSQUIRRELVM v, SQUserPointer p)
:param HSQUIRRELVM v: the target VM
:param SQUserPointer p: the pointer that as to be pushed
pushes a userpointer into the stack
.. _sq_setbyhandle:
.. c:function:: SQRESULT sq_setbyhandle(HSQUIRRELVM v, SQInteger idx, HSQMEMBERHANDLE* handle)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: an index in the stack pointing to the class
:param HSQMEMBERHANDLE* handle: a pointer the member handle
:returns: a SQRESULT
pops a value from the stack and sets it to a class or instance member using a member handle (see sq_getmemberhandle)
.. _sq_setclassudsize:
.. c:function:: SQRESULT sq_setclassudsize(HSQUIRRELVM v, SQInteger idx, SQInteger udsize)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: an index in the stack pointing to the class
:param SQInteger udsize: size in bytes reserved for user data
:returns: a SQRESULT
Sets the user data size of a class. If a class 'user data size' is greater than 0. When an instance of the class is created additional space will be reserved at the end of the memory chunk where the instance is stored. The userpointer of the instance will also be automatically set to this memory area. This allows you to minimize allocations in applications that have to carry data along with the class instance.
.. _sq_setclosureroot:
.. c:function:: SQRESULT sq_setclosureroot(HSQUIRRELVM v, SQInteger idx)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: index of the target closure
:returns: an SQRESULT
pops a table from the stack and sets it as root of the closure at position idx in the stack
.. _sq_setinstanceup:
.. c:function:: SQRESULT sq_setinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer up)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: an index in the stack
:param SQUserPointer up: an arbitrary user pointer
:returns: a SQRESULT
sets the userpointer of the class instance at position idx in the stack.
.. _sq_setnativeclosurename:
.. c:function:: SQRESULT sq_setnativeclosurename(HSQUIRRELVM v, SQInteger idx, const SQChar * name)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: index of the target native closure
:param const SQChar * name: the name that has to be set
:returns: an SQRESULT
sets the name of the native closure at the position idx in the stack. The name of a native closure is purely for debug purposes. The name is retrieved through the function sq_stackinfos() while the closure is in the call stack.
.. _sq_setparamscheck:
.. c:function:: SQRESULT sq_setparamscheck(HSQUIRRELVM v, SQInteger nparamscheck, const SQChar * typemask)
:param HSQUIRRELVM v: the target VM
:param SQInteger nparamscheck: defines the parameters number check policy (0 disables the param checking). If nparamscheck is greater than 0, the VM ensures that the number of parameters is exactly the number specified in nparamscheck (eg. if nparamscheck == 3 the function can only be called with 3 parameters). If nparamscheck is less than 0 the VM ensures that the closure is called with at least the absolute value of the number specified in nparamcheck (eg. nparamscheck == -3 will check that the function is called with at least 3 parameters). The hidden parameter 'this' is included in this number; free variables aren't. If SQ_MATCHTYPEMASKSTRING is passed instead of the number of parameters, the function will automatically infer the number of parameters to check from the typemask (eg. if the typemask is ".sn", it is like passing 3).
:param const SQChar * typemask: defines a mask to validate the parametes types passed to the function. If the parameter is NULL, no typechecking is applied (default).
:remarks: The typemask consists in a zero terminated string that represent the expected parameter type. The types are expressed as follows: 'o' null, 'i' integer, 'f' float, 'n' integer or float, 's' string, 't' table, 'a' array, 'u' userdata, 'c' closure and nativeclosure, 'g' generator, 'p' userpointer, 'v' thread, 'x' instance(class instance), 'y' class, 'b' bool. and '.' any type. The symbol '|' can be used as 'or' to accept multiple types on the same parameter. There isn't any limit on the number of 'or' that can be used. Spaces are ignored so can be inserted between types to increase readability. For instance to check a function that expect a table as 'this' a string as first parameter and a number or a userpointer as second parameter, the string would be "tsn|p" (table,string,number or userpointer). If the parameters mask is contains fewer parameters than 'nparamscheck', the remaining parameters will not be typechecked.
Sets the parameter validation scheme for the native closure at the top position in the stack. Allows you to validate the number of parameters accepted by the function and optionally their types. If the function call does not comply with the parameter schema set by sq_setparamscheck, an exception is thrown.
*.eg*
::
//example
SQInteger testy(HSQUIRRELVM v)
{
SQUserPointer p;
const SQChar *s;
SQInteger i;
//no type checking, if the call complies with the mask
//surely the functions will succeed.
sq_getuserdata(v,1,&p,NULL);
sq_getstring(v,2,&s);
sq_getinteger(v,3,&i);
//... do something
return 0;
}
//the reg code
//....stuff
sq_newclosure(v,testy,0);
//expects exactly 3 parameters(userdata,string,number)
sq_setparamscheck(v,3,_SC("usn"));
//....stuff
.. _sq_setreleasehook:
.. c:function:: void sq_setreleasehook(HSQUIRRELVM v, SQInteger idx, SQRELEASEHOOK hook)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: an index in the stack
:param SQRELEASEHOOK hook: a function pointer to the hook(see sample below)
:remarks: the function hook is called by the VM before the userdata memory is deleted.
sets the release hook of the userdata, class instance, or class at position idx in the stack.
*.eg*
::
/* tyedef SQInteger (*SQRELEASEHOOK)(SQUserPointer,SQInteger size); */
SQInteger my_release_hook(SQUserPointer p,SQInteger size)
{
/* do something here */
return 1;
}
.. _sq_settypetag:
.. c:function:: SQRESULT sq_settypetag(HSQUIRRELVM v, SQInteger idx, SQUserPointer typetag)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: an index in the stack
:param SQUserPointer typetag: an arbitrary SQUserPointer
:returns: a SQRESULT
sets the typetag of the object (userdata or class) at position idx in the stack.
.. _sq_tobool:
.. c:function:: void sq_tobool(HSQUIRRELVM v, SQInteger idx, SQBool * b)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: an index in the stack
:param SQBool * b: A pointer to the bool that will store the value
:remarks: if the object is not a bool the function converts the value to bool according to squirrel's rules. For instance the number 1 will result in true, and the number 0 in false.
gets the value at position idx in the stack as bool.
.. _sq_tostring:
.. c:function:: void sq_tostring(HSQUIRRELVM v, SQInteger idx)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: an index in the stack
converts the object at position idx in the stack to string and pushes the resulting string in the stack.
.. _sq_typeof:
.. c:function:: SQObjectType sq_typeof(HSQUIRRELVM v, SQInteger idx)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: an index in the stack
:returns: a SQRESULT
pushes the type name of the value at the position idx in the stack. It also invokes the _typeof metamethod for tables and class instances that implement it; in that case the pushed object could be something other than a string (is up to the _typeof implementation).

View File

@ -0,0 +1,451 @@
.. _api_ref_object_manipulation:
====================
Object manipulation
====================
.. _sq_arrayappend:
.. c:function:: SQRESULT sq_arrayappend(HSQUIRRELVM v, SQInteger idx)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: index of the target array in the stack
:returns: a SQRESULT
:remarks: Only works on arrays.
pops a value from the stack and pushes it in the back of the array at the position idx in the stack.
.. _sq_arrayinsert:
.. c:function:: SQRESULT sq_arrayinsert(HSQUIRRELVM v, SQInteger idx, SQInteger destpos)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: index of the target array in the stack
:param SQInteger destpos: the position in the array where the item has to be inserted
:returns: a SQRESULT
:remarks: Only works on arrays.
pops a value from the stack and inserts it in an array at the specified position
.. _sq_arraypop:
.. c:function:: SQRESULT sq_arraypop(HSQUIRRELVM v, SQInteger idx)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: index of the target array in the stack
:returns: a SQRESULT
:remarks: Only works on arrays.
pops a value from the back of the array at the position idx in the stack.
.. _sq_arrayremove:
.. c:function:: SQRESULT sq_arrayremove(HSQUIRRELVM v, SQInteger idx, SQInteger itemidx)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: index of the target array in the stack
:param SQInteger itemidx: the index of the item in the array that has to be removed
:returns: a SQRESULT
:remarks: Only works on arrays.
removes an item from an array
.. _sq_arrayresize:
.. c:function:: SQRESULT sq_arrayresize(HSQUIRRELVM v, SQInteger idx, SQInteger newsize)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: index of the target array in the stack
:param SQInteger newsize: requested size of the array
:returns: a SQRESULT
:remarks: Only works on arrays. If newsize if greater than the current size the new array slots will be filled with nulls.
resizes the array at the position idx in the stack.
.. _sq_arrayreverse:
.. c:function:: SQRESULT sq_arrayreverse(HSQUIRRELVM v, SQInteger idx)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: index of the target array in the stack
:returns: a SQRESULT
:remarks: Only works on arrays.
reverses an array in place.
.. _sq_clear:
.. c:function:: SQRESULT sq_clear(HSQUIRRELVM v, SQInteger idx)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: index of the target object in the stack
:returns: a SQRESULT
:remarks: Only works on tables and arrays.
clears all the elements of the table/array at position idx in the stack.
.. _sq_clone:
.. c:function:: SQRESULT sq_clone(HSQUIRRELVM v, SQInteger idx)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: index of the target object in the stack
:returns: a SQRESULT
pushes a clone of the table, array, or class instance at the position idx.
.. _sq_createslot:
.. c:function:: SQRESULT sq_createslot(HSQUIRRELVM v, SQInteger idx)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: index of the target table in the stack
:returns: a SQRESULT
:remarks: invoke the _newslot metamethod in the table delegate. it only works on tables. [this function is deperecated since version 2.0.5 use sq_newslot() instead]
pops a key and a value from the stack and performs a set operation on the table or class that is at position idx in the stack; if the slot does not exist, it will be created.
.. _sq_deleteslot:
.. c:function:: SQRESULT sq_deleteslot(HSQUIRRELVM v, SQInteger idx, SQBool pushval)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: index of the target table in the stack
:param SQBool pushval: if this param is true the function will push the value of the deleted slot.
:returns: a SQRESULT
:remarks: invoke the _delslot metamethod in the table delegate. it only works on tables.
pops a key from the stack and delete the slot indexed by it from the table at position idx in the stack; if the slot does not exist, nothing happens.
.. _sq_get:
.. c:function:: SQRESULT sq_get(HSQUIRRELVM v, SQInteger idx)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: index of the target object in the stack
:returns: a SQRESULT
:remarks: this call will invokes the delegation system like a normal dereference it only works on tables, arrays, classes, instances and userdata; if the function fails, nothing will be pushed in the stack.
pops a key from the stack and performs a get operation on the object at the position idx in the stack; and pushes the result in the stack.
.. _sq_getattributes:
.. c:function:: SQRESULT sq_getattributes(HSQUIRRELVM v, SQInteger idx)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: index of the target class in the stack
:returns: a SQRESULT
Gets the attribute of a class member. The function pops a key from the stack and pushes the attribute of the class member indexed by they key from a class at position idx in the stack. If key is null the function gets the class level attribute.
.. _sq_getbase:
.. c:function:: SQRESULT sq_getbase(HSQUIRRELVM v, SQInteger idx)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: index of the target class in the stack
:returns: a SQRESULT
pushes the base class of the 'class' at stored position idx in the stack.
.. _sq_getclass:
.. c:function:: SQRESULT sq_getclass(HSQUIRRELVM v, SQInteger idx)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: index of the target class instance in the stack
:returns: a SQRESULT
pushes the class of the 'class instance' at stored position idx in the stack.
.. _sq_getdelegate:
.. c:function:: SQRESULT sq_getdelegate(HSQUIRRELVM v, SQInteger idx)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: index of the target object in the stack
:returns: a SQRESULT
pushes the current delegate of the object at the position idx in the stack.
.. _sq_getfreevariable:
.. c:function:: const SQChar * sq_getfreevariable(HSQUIRRELVM v, SQInteger idx, SQInteger nval)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: index of the target object in the stack(closure)
:param SQInteger nval: 0 based index of the free variable(relative to the closure).
:returns: the name of the free variable for pure squirrel closures. NULL in case of error or if the index of the variable is out of range. In case the target closure is a native closure, the return name is always "@NATIVE".
:remarks: The function works for both squirrel closure and native closure.
gets the value of the free variable of the closure at the position idx in the stack.
.. _sq_getweakrefval:
.. c:function:: SQRESULT sq_getweakrefval(HSQUIRRELVM v, SQInteger idx)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: index of the target weak reference
:returns: a SQRESULT
:remarks: if the function fails, nothing is pushed in the stack.
pushes the object pointed by the weak reference at position idx in the stack.
.. _sq_instanceof:
.. c:function:: SQBool sq_instanceof(HSQUIRRELVM v)
:param HSQUIRRELVM v: the target VM
:returns: SQTrue if the instance at position -2 in the stack is an instance of the class object at position -1 in the stack.
:remarks: The function doesn't pop any object from the stack.
Determines if an object is an instance of a certain class. Expects an instance and a class in the stack.
.. _sq_newmember:
.. c:function:: SQRESULT sq_newmember(HSQUIRRELVM v, SQInteger idx, SQBool bstatic)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: index of the target table in the stack
:param SQBool bstatic: if SQTrue creates a static member.
:returns: a SQRESULT
:remarks: Invokes the _newmember metamethod in the class. it only works on classes.
pops a key, a value and an object (which will be set as attribute of the member) from the stack and performs a new slot operation on the class that is at position idx in the stack; if the slot does not exist, it will be created.
.. _sq_newslot:
.. c:function:: SQRESULT sq_newslot(HSQUIRRELVM v, SQInteger idx, SQBool bstatic)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: index of the target table in the stack
:param SQBool bstatic: if SQTrue creates a static member. This parameter is only used if the target object is a class.
:returns: a SQRESULT
:remarks: Invokes the _newslot metamethod in the table delegate. it only works on tables and classes.
pops a key and a value from the stack and performs a set operation on the table or class that is at position idx in the stack, if the slot does not exist it will be created.
.. _sq_next:
.. c:function:: SQRESULT sq_next(HSQUIRRELVM v, SQInteger idx)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: index of the target object in the stack
:returns: a SQRESULT
Pushes in the stack the next key and value of an array, table, or class slot. To start the iteration this function expects a null value on top of the stack; at every call the function will substitute the null value with an iterator and push key and value of the container slot. Every iteration the application has to pop the previous key and value but leave the iterator(that is used as reference point for the next iteration). The function will fail when all slots have been iterated(see Tables and arrays manipulation).
.. _sq_rawdeleteslot:
.. c:function:: SQRESULT sq_rawdeleteslot(HSQUIRRELVM v, SQInteger idx, SQBool pushval)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: index of the target table in the stack
:param SQBool pushval: if this param is true the function will push the value of the deleted slot.
:returns: a SQRESULT
Deletes a slot from a table without employing the _delslot metamethod. Pops a key from the stack and delete the slot indexed by it from the table at position idx in the stack; if the slot does not exist nothing happens.
.. _sq_rawget:
.. c:function:: SQRESULT sq_rawget(HSQUIRRELVM v, SQInteger idx)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: index of the target object in the stack
:returns: a SQRESULT
:remarks: Only works on tables and arrays.
pops a key from the stack and performs a get operation on the object at position idx in the stack, without employing delegation or metamethods.
.. _sq_rawnewmember:
.. c:function:: SQRESULT sq_rawnewmember(HSQUIRRELVM v, SQInteger idx, SQBool bstatic)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: index of the target table in the stack
:param SQBool bstatic: if SQTrue creates a static member.
:returns: a SQRESULT
:remarks: it only works on classes.
pops a key, a value and an object(that will be set as attribute of the member) from the stack and performs a new slot operation on the class that is at position idx in the stack; if the slot does not exist it will be created.
.. _sq_rawset:
.. c:function:: SQRESULT sq_rawset(HSQUIRRELVM v, SQInteger idx)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: index of the target object in the stack
:returns: a SQRESULT
:remarks: it only works on tables and arrays. if the function fails nothing will be pushed in the stack.
pops a key and a value from the stack and performs a set operation on the object at position idx in the stack, without employing delegation or metamethods.
.. _sq_set:
.. c:function:: SQRESULT sq_set(HSQUIRRELVM v, SQInteger idx)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: index of the target object in the stack
:returns: a SQRESULT
:remarks: this call will invoke the delegation system like a normal assignment, it only works on tables, arrays and userdata.
pops a key and a value from the stack and performs a set operation on the object at position idx in the stack.
.. _sq_setattributes:
.. c:function:: SQRESULT sq_setattributes(HSQUIRRELVM v, SQInteger idx)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: index of the target class in the stack.
:returns: a SQRESULT
Sets the attribute of a class member. The function pops a key and a value from the stack and sets the attribute (indexed by the key) on the class at position idx in the stack. If key is null the function sets the class level attribute. If the function succeed, the old attribute value is pushed in the stack.
.. _sq_setdelegate:
.. c:function:: SQRESULT sq_setdelegate(HSQUIRRELVM v, SQInteger idx)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: index of the target object in the stack
:returns: a SQRESULT
:remarks: to remove the delegate from an object, set a null value.
pops a table from the stack and sets it as the delegate of the object at the position idx in the stack.
.. _sq_setfreevariable:
.. c:function:: SQRESULT sq_setfreevariable(HSQUIRRELVM v, SQInteger idx, SQInteger nval)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: index of the target object in the stack
:param SQInteger nval: 0 based index of the free variable(relative to the closure).
:returns: a SQRESULT
pops a value from the stack and sets it as a free variable of the closure at the position idx in the stack.
.. _sq_weakref:
.. c:function:: void sq_weakref(HSQUIRRELVM v, SQInteger idx)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: index to the target object in the stack
:returns: a SQRESULT
:remarks: if the object at idx position is one of (integer, float, bool, null), the object itself is pushed instead of a weak ref.
pushes a weak reference to the object at position idx in the stack.

View File

@ -0,0 +1,163 @@
.. _api_ref_raw_object_handling:
===================
Raw object handling
===================
.. _sq_addref:
.. c:function:: void sq_addref(HSQUIRRELVM v, HSQOBJECT* po)
:param HSQUIRRELVM v: the target VM
:param HSQOBJECT* po: pointer to an object handler
adds a reference to an object handler.
.. _sq_getobjtypetag:
.. c:function:: SQRESULT sq_getobjtypetag(HSQOBJECT* o, SQUserPointer* typetag)
:param HSQOBJECT* o: pointer to an object handler
:param SQUserPointer* typetag: a pointer to the variable that will store the tag
:returns: a SQRESULT
:remarks: the function works also with instances. if the target object is an instance, the typetag of it's base class is fetched.
gets the typetag of a raw object reference(userdata or class).
.. _sq_getrefcount:
.. c:function:: SQUnsignedInteger sq_getrefcount(HSQUIRRELVM v, HSQOBJECT* po)
:param HSQUIRRELVM v: the target VM
:param HSQOBJECT* po: object handler
returns the number of references of a given object.
.. _sq_getstackobj:
.. c:function:: SQRESULT sq_getstackobj(HSQUIRRELVM v, SQInteger idx, HSQOBJECT* po)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: index of the target object in the stack
:param HSQOBJECT* po: pointer to an object handler
:returns: a SQRESULT
gets an object from the stack and stores it in a object handler.
.. _sq_objtobool:
.. c:function:: SQBool sq_objtobool(HSQOBJECT* po)
:param HSQOBJECT* po: pointer to an object handler
:remarks: If the object is not a bool will always return false.
return the bool value of a raw object reference.
.. _sq_objtofloat:
.. c:function:: SQFloat sq_objtofloat(HSQOBJECT* po)
:param HSQOBJECT* po: pointer to an object handler
:remarks: If the object is an integer will convert it to float. If the object is not a number will always return 0.
return the float value of a raw object reference.
.. _sq_objtointeger:
.. c:function:: SQInteger sq_objtointeger(HSQOBJECT* po)
:param HSQOBJECT* po: pointer to an object handler
:remarks: If the object is a float will convert it to integer. If the object is not a number will always return 0.
return the integer value of a raw object reference.
.. _sq_objtostring:
.. c:function:: const SQChar* sq_objtostring(HSQOBJECT* po)
:param HSQOBJECT* po: pointer to an object handler
:remarks: If the object doesn't reference a string it returns NULL.
return the string value of a raw object reference.
.. _sq_objtouserpointer:
.. c:function:: SQUserPointer sq_objtouserpointer(HSQOBJECT* po)
:param HSQOBJECT* po: pointer to an object handler
:remarks: If the object doesn't reference a userpointer it returns NULL.
return the userpointer value of a raw object reference.
.. _sq_pushobject:
.. c:function:: void sq_pushobject(HSQUIRRELVM v, HSQOBJECT obj)
:param HSQUIRRELVM v: the target VM
:param HSQOBJECT obj: object handler
push an object referenced by an object handler into the stack.
.. _sq_release:
.. c:function:: SQBool sq_release(HSQUIRRELVM v, HSQOBJECT* po)
:param HSQUIRRELVM v: the target VM
:param HSQOBJECT* po: pointer to an object handler
:returns: SQTrue if the object handler released has lost all is references(the ones added with sq_addref). SQFalse otherwise.
:remarks: the function will reset the object handler to null when it loses all references.
remove a reference from an object handler.
.. _sq_resetobject:
.. c:function:: void sq_resetobject(HSQOBJECT* po)
:param HSQOBJECT* po: pointer to an object handler
:remarks: Every object handler has to be initialized with this function.
resets(initialize) an object handler.

View File

@ -0,0 +1,107 @@
.. _api_ref_stack_operations:
================
Stack Operations
================
.. _sq_cmp:
.. c:function:: SQInteger sq_cmp(HSQUIRRELVM v)
:param HSQUIRRELVM v: the target VM
:returns: > 0 if obj1>obj2
:returns: == 0 if obj1==obj2
:returns: < 0 if obj1<obj2
compares 2 object from the top of the stack. obj2 should be pushed before obj1.
.. _sq_gettop:
.. c:function:: SQInteger sq_gettop(HSQUIRRELVM v)
:param HSQUIRRELVM v: the target VM
:returns: an integer representing the index of the top of the stack
returns the index of the top of the stack
.. _sq_pop:
.. c:function:: void sq_pop(HSQUIRRELVM v, SQInteger nelementstopop)
:param HSQUIRRELVM v: the target VM
:param SQInteger nelementstopop: the number of elements to pop
pops n elements from the stack
.. _sq_poptop:
.. c:function:: void sq_poptop(HSQUIRRELVM v)
:param HSQUIRRELVM v: the target VM
pops 1 object from the stack
.. _sq_push:
.. c:function:: void sq_push(HSQUIRRELVM v, SQInteger idx)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: the index in the stack of the value that has to be pushed
pushes in the stack the value at the index idx
.. _sq_remove:
.. c:function:: void sq_remove(HSQUIRRELVM v, SQInteger idx)
:param HSQUIRRELVM v: the target VM
:param SQInteger idx: index of the element that has to be removed
removes an element from an arbitrary position in the stack
.. _sq_reservestack:
.. c:function:: SQRESULT sq_reservestack(HSQUIRRELVM v, SQInteger nsize)
:param HSQUIRRELVM v: the target VM
:param SQInteger nsize: required stack size
:returns: a SQRESULT
ensure that the stack space left is at least of a specified size.If the stack is smaller it will automatically grow. If there's a metamethod currently running the function will fail and the stack will not be resized, this situation has to be considered a "stack overflow".
.. _sq_settop:
.. c:function:: void sq_settop(HSQUIRRELVM v, SQInteger v)
:param HSQUIRRELVM v: the target VM
:param SQInteger v: the new top index
resize the stack. If new top is bigger then the current top the function will push nulls.

View File

@ -0,0 +1,341 @@
.. _api_ref_virtual_machine:
===============
Virtual Machine
===============
.. _sq_close:
.. c:function:: void sq_close(HSQUIRRELVM v)
:param HSQUIRRELVM v: the target VM
releases a squirrel VM and all related friend VMs
.. _sq_geterrorfunc:
.. c:function:: SQPRINTFUNCTION sq_geterrorfunc(HSQUIRRELVM v)
:param HSQUIRRELVM v: the target VM
:returns: a pointer to a SQPRINTFUNCTION, or NULL if no function has been set.
returns the current error function of the given Virtual machine. (see sq_setprintfunc())
.. _sq_getforeignptr:
.. c:function:: SQUserPointer sq_getforeignptr(HSQUIRRELVM v)
:param HSQUIRRELVM v: the target VM
:returns: the current VMs foreign pointer.
Returns the foreign pointer of a VM instance.
.. _sq_getprintfunc:
.. c:function:: SQPRINTFUNCTION sq_getprintfunc(HSQUIRRELVM v)
:param HSQUIRRELVM v: the target VM
:returns: a pointer to a SQPRINTFUNCTION, or NULL if no function has been set.
returns the current print function of the given Virtual machine. (see sq_setprintfunc())
.. _sq_getsharedforeignptr:
.. c:function:: SQUserPointer sq_getsharedforeignptr(HSQUIRRELVM v)
:param HSQUIRRELVM v: the target VM
:returns: the current VMs shared foreign pointer
Returns the shared foreign pointer of a group of friend VMs
.. _sq_getsharedreleasehook:
.. c:function:: SQUserPointer sq_getsharedreleasehook(HSQUIRRELVM v)
:param HSQUIRRELVM v: the target VM
:returns: the current VMs release hook.
Returns the shared release hook of a group of friend VMs
.. _sq_getversion:
.. c:function:: SQInteger sq_getversion()
:returns: version number of the vm(as in SQUIRREL_VERSION_NUMBER).
returns the version number of the vm
.. _sq_getvmreleasehook:
.. c:function:: SQUserPointer sq_getvmreleasehook(HSQUIRRELVM v)
:param HSQUIRRELVM v: the target VM
:returns: the current VMs release hook.
Returns the release hook of a VM instance
.. _sq_getvmstate:
.. c:function:: SQInteger sq_getvmstate(HSQUIRRELVM v)
:param HSQUIRRELVM v: the target VM
:returns: the state of the vm encoded as integer value. The following constants are defined: SQ_VMSTATE_IDLE, SQ_VMSTATE_RUNNING, SQ_VMSTATE_SUSPENDED.
returns the execution state of a virtual machine
.. _sq_move:
.. c:function:: void sq_move(HSQUIRRELVM dest, HSQUIRRELVM src, SQInteger idx)
:param HSQUIRRELVM dest: the destination VM
:param HSQUIRRELVM src: the source VM
:param SQInteger idx: the index in the source stack of the value that has to be moved
pushes the object at the position 'idx' of the source vm stack in the destination vm stack
.. _sq_newthread:
.. c:function:: HSQUIRRELVM sq_newthread(HSQUIRRELVM friendvm, SQInteger initialstacksize)
:param HSQUIRRELVM friendvm: a friend VM
:param SQInteger initialstacksize: the size of the stack in slots(number of objects)
:returns: a pointer to the new VM.
:remarks: By default the roottable is shared with the VM passed as first parameter. The new VM lifetime is bound to the "thread" object pushed in the stack and behave like a normal squirrel object.
creates a new vm friendvm of the one passed as first parmeter and pushes it in its stack as "thread" object.
.. _sq_open:
.. c:function:: HSQUIRRELVM sq_open(SQInteger initialstacksize)
:param SQInteger initialstacksize: the size of the stack in slots(number of objects)
:returns: an handle to a squirrel vm
:remarks: the returned VM has to be released with sq_releasevm
creates a new instance of a squirrel VM that consists in a new execution stack.
.. _sq_pushconsttable:
.. c:function:: void sq_pushconsttable(HSQUIRRELVM v)
:param HSQUIRRELVM v: the target VM
pushes the current const table in the stack
.. _sq_pushregistrytable:
.. c:function:: void sq_pushregistrytable(HSQUIRRELVM v)
:param HSQUIRRELVM v: the target VM
pushes the registry table in the stack
.. _sq_pushroottable:
.. c:function:: void sq_pushroottable(HSQUIRRELVM v)
:param HSQUIRRELVM v: the target VM
pushes the current root table in the stack
.. _sq_setconsttable:
.. c:function:: void sq_setconsttable(HSQUIRRELVM v)
:param HSQUIRRELVM v: the target VM
pops a table from the stack and set it as const table
.. _sq_seterrorhandler:
.. c:function:: void sq_seterrorhandler(HSQUIRRELVM v)
:param HSQUIRRELVM v: the target VM
:remarks: the error handler is shared by friend VMs
pops from the stack a closure or native closure an sets it as runtime-error handler.
.. _sq_setforeignptr:
.. c:function:: void sq_setforeignptr(HSQUIRRELVM v, SQUserPointer p)
:param HSQUIRRELVM v: the target VM
:param SQUserPointer p: The pointer that has to be set
Sets the foreign pointer of a certain VM instance. The foreign pointer is an arbitrary user defined pointer associated to a VM (by default is value id 0). This pointer is ignored by the VM.
.. _sq_setprintfunc:
.. c:function:: void sq_setprintfunc(HSQUIRRELVM v, SQPRINTFUNCTION printfunc, SQPRINTFUNCTION errorfunc)
:param HSQUIRRELVM v: the target VM
:param SQPRINTFUNCTION printfunc: a pointer to the print func or NULL to disable the output.
:param SQPRINTFUNCTION errorfunc: a pointer to the error func or NULL to disable the output.
:remarks: the print func has the following prototype: void printfunc(HSQUIRRELVM v,const SQChar \*s,...)
sets the print function of the virtual machine. This function is used by the built-in function '::print()' to output text.
.. _sq_setroottable:
.. c:function:: void sq_setroottable(HSQUIRRELVM v)
:param HSQUIRRELVM v: the target VM
pops a table from the stack and set it as root table
.. _sq_setsharedforeignptr:
.. c:function:: void sq_setsharedforeignptr(HSQUIRRELVM v, SQUserPointer p)
:param HSQUIRRELVM v: the target VM
:param SQUserPointer p: The pointer that has to be set
Sets the shared foreign pointer. The foreign pointer is an arbitrary user defined pointer associated to a group of friend VMs (by default is value id 0). After a "main" VM is created using sq_open() all friend VMs created with sq_newthread share the same shared pointer.
.. _sq_setsharedreleasehook:
.. c:function:: void sq_setsharedreleasehook(HSQUIRRELVM v, SQRELESEHOOK hook)
:param HSQUIRRELVM v: the target VM
:param SQRELESEHOOK hook: The hook that has to be set
Sets the release hook of a certain VM group. The release hook is invoked when the last vm of the group vm is destroyed (usually when sq_close() is invoked). The userpointer passed to the function is the shared foreignpointer(see sq_getsharedforeignptr()). After a "main" VM is created using sq_open() all friend VMs created with sq_newthread() share the same shared release hook.
.. _sq_setvmreleasehook:
.. c:function:: void sq_setvmreleasehook(HSQUIRRELVM v, SQRELESEHOOK hook)
:param HSQUIRRELVM v: the target VM
:param SQRELESEHOOK hook: The hook that has to be set
Sets the release hook of a certain VM instance. The release hook is invoked when the vm is destroyed. The userpointer passed to the function is the vm foreignpointer (see sq_setforeignpointer())
.. _sq_suspendvm:
.. c:function:: HRESULT sq_suspendvm(HSQUIRRELVM v)
:param HSQUIRRELVM v: the target VM
:returns: an SQRESULT(that has to be returned by a C function)
:remarks: sq_result can only be called as return expression of a C function. The function will fail is the suspension is done through more C calls or in a metamethod.
Suspends the execution of the specified vm.
*.eg*
::
SQInteger suspend_vm_example(HSQUIRRELVM v)
{
return sq_suspendvm(v);
}
.. _sq_wakeupvm:
.. c:function:: HRESULT sq_wakeupvm(HSQUIRRELVM v, SQBool resumedret, SQBool retval, SQBool raiseerror, SQBool throwerror)
:param HSQUIRRELVM v: the target VM
:param SQBool resumedret: if true the function will pop a value from the stack and use it as return value for the function that has previously suspended the virtual machine.
:param SQBool retval: if true the function will push the return value of the function that suspend the excution or the main function one.
:param SQBool raiseerror: if true, if a runtime error occurs during the execution of the call, the vm will invoke the error handler.
:param SQBool throwerror: if true, the vm will thow an exception as soon as is resumed. the exception payload must be set beforehand invoking sq_thowerror().
:returns: an HRESULT.
wake up the execution a previously suspended virtual machine

View File

@ -0,0 +1,18 @@
.. _api_reference:
*************
API Reference
*************
.. toctree::
api/virtual_machine.rst
api/compiler.rst
api/stack_operations.rst
api/object_creation_and_handling.rst
api/calls.rst
api/object_manipulation.rst
api/bytecode_serialization.rst
api/raw_object_handling.rst
api/garbage_collector.rst
api/debug_interface.rst

View File

@ -0,0 +1,59 @@
.. _embedding_build_configuration:
========================
Build Configuration
========================
.. _unicode:
----------
Unicode
----------
.. index:: single: Unicode
By default Squirrel strings are plain 8-bits ASCII characters; however if the symbol
'SQUNICODE' is defined the VM, compiler and API will use 16-bit characters (UCS2).
.. _squirrel_64bits:
--------------------------------
Squirrel on 64-bit architectures
--------------------------------
.. index::
single: Squirrel on 64-bit architectures
single: 64 bits
Squirrel can be compiled on 64-bit architectures by defining '_SQ64' in the C++
preprocessor. This flag should be defined in any project that includes 'squirrel.h'.
.. _userdata_alignment:
------------------
Userdata Alignment
------------------
.. index:: single: Userdata Alignment
Both class instances and userdatas can have a buffer associated to them.
Squirrel specifies the alignment(in bytes) through the preprocessor defining 'SQ_ALIGNMENT'.
By default SQ_ALIGNMENT is defined as 4 for 32-bit builds and 8 for 64-bit builds and builds that use 64-bit floats.
It is possible to override the value of SQ_ALIGNMENT respecting the following rules.
SQ_ALIGNMENT shall be less than or equal to SQ_MALLOC alignments, and it shall be power of 2.
.. note:: This only applies for userdata allocated by the VM, specified via sq_setclassudsize() or belonging to a userdata object.
userpointers specified by the user are not affected by alignment rules.
.. _standalone_vm:
------------------------------------
Stand-alone VM without compiler
------------------------------------
.. index:: single: Stand-alone VM without compiler
Squirrel's VM can be compiled without its compiler by defining 'NO_COMPILER' in the C++ preprocessor.
When 'NO_COMPILER' is defined all function related to the compiler (eg. sq_compile) will fail. Other functions
that conditionally load precompiled bytecode or compile a file (eg. sqstd_dofile) will only work with
precompiled bytecode.

View File

@ -0,0 +1,27 @@
.. _embedding_calling_a_function:
==================
Calling a function
==================
To call a squirrel function it is necessary to push the function in the stack followed by the
parameters and then call the function sq_call.
The function will pop the parameters and push the return value if the last sq_call
parameter is > 0. ::
sq_pushroottable(v);
sq_pushstring(v,"foo",-1);
sq_get(v,-2); //get the function from the root table
sq_pushroottable(v); //'this' (function environment object)
sq_pushinteger(v,1);
sq_pushfloat(v,2.0);
sq_pushstring(v,"three",-1);
sq_call(v,4,SQFalse,SQFalse);
sq_pop(v,2); //pops the roottable and the function
this is equivalent to the following Squirrel code::
foo(1,2.0,"three");
If a runtime error occurs (or a exception is thrown) during the squirrel code execution
the sq_call will fail.

View File

@ -0,0 +1,58 @@
.. embedding_compiling_a_script:
==================
Compiling a script
==================
You can compile a Squirrel script with the function *sq_compile*.::
typedef SQInteger (*SQLEXREADFUNC)(SQUserPointer userdata);
SQRESULT sq_compile(HSQUIRRELVM v,SQLEXREADFUNC read,SQUserPointer p,
const SQChar *sourcename,SQBool raiseerror);
In order to compile a script is necessary for the host application to implement a reader
function (SQLEXREADFUNC); this function is used to feed the compiler with the script
data.
The function is called every time the compiler needs a character; It has to return a
character code if succeed or 0 if the source is finished.
If sq_compile succeeds, the compiled script will be pushed as Squirrel function in the
stack.
.. :note::
In order to execute the script, the function generated by *sq_compile()* has
to be called through *sq_call()*
Here an example of a 'read' function that read from a file: ::
SQInteger file_lexfeedASCII(SQUserPointer file)
{
int ret;
char c;
if( ( ret=fread(&c,sizeof(c),1,(FILE *)file )>0) )
return c;
return 0;
}
int compile_file(HSQUIRRELVM v,const char *filename)
{
FILE *f=fopen(filename,"rb");
if(f)
{
sq_compile(v,file_lexfeedASCII,f,filename,1);
fclose(f);
return 1;
}
return 0;
}
When the compiler fails for a syntax error it will try to call the 'compiler error handler';
this function must be declared as follow: ::
typedef void (*SQCOMPILERERROR)(HSQUIRRELVM /*v*/,const SQChar * /*desc*/,const SQChar * /*source*/,
SQInteger /*line*/,SQInteger /*column*/);
and can be set with the following API call::
void sq_setcompilererrorhandler(HSQUIRRELVM v,SQCOMPILERERROR f);

View File

@ -0,0 +1,106 @@
.. _embedding_creating_a_c_function:
===================
Create a C function
===================
A native C function must have the following prototype: ::
typedef SQInteger (*SQFUNCTION)(HSQUIRRELVM);
The parameters is an handle to the calling VM and the return value is an integer
respecting the following rules:
* 1 if the function returns a value
* 0 if the function does not return a value
* SQ_ERROR runtime error is thrown
In order to obtain a new callable squirrel function from a C function pointer, is necessary
to call sq_newclosure() passing the C function to it; the new Squirrel function will be
pushed in the stack.
When the function is called, the stackbase is the first parameter of the function and the
top is the last. In order to return a value the function has to push it in the stack and
return 1.
Function parameters are in the stack from position 1 ('this') to *n*.
*sq_gettop()* can be used to determinate the number of parameters.
If the function has free variables, those will be in the stack after the explicit parameters
an can be handled as normal parameters. Note also that the value returned by *sq_gettop()* will be
affected by free variables. *sq_gettop()* will return the number of parameters plus
number of free variables.
Here an example, the following function print the value of each argument and return the
number of arguments. ::
SQInteger print_args(HSQUIRRELVM v)
{
SQInteger nargs = sq_gettop(v); //number of arguments
for(SQInteger n=1;n<=nargs;n++)
{
printf("arg %d is ",n);
switch(sq_gettype(v,n))
{
case OT_NULL:
printf("null");
break;
case OT_INTEGER:
printf("integer");
break;
case OT_FLOAT:
printf("float");
break;
case OT_STRING:
printf("string");
break;
case OT_TABLE:
printf("table");
break;
case OT_ARRAY:
printf("array");
break;
case OT_USERDATA:
printf("userdata");
break;
case OT_CLOSURE:
printf("closure(function)");
break;
case OT_NATIVECLOSURE:
printf("native closure(C function)");
break;
case OT_GENERATOR:
printf("generator");
break;
case OT_USERPOINTER:
printf("userpointer");
break;
case OT_CLASS:
printf("class");
break;
case OT_INSTANCE:
printf("instance");
break;
case OT_WEAKREF:
printf("weak reference");
break;
default:
return sq_throwerror(v,"invalid param"); //throws an exception
}
}
printf("\n");
sq_pushinteger(v,nargs); //push the number of arguments as return value
return 1; //1 because 1 value is returned
}
Here an example of how to register a function::
SQInteger register_global_func(HSQUIRRELVM v,SQFUNCTION f,const char *fname)
{
sq_pushroottable(v);
sq_pushstring(v,fname,-1);
sq_newclosure(v,f,0); //create a new function
sq_newslot(v,-3,SQFalse);
sq_pop(v,1); //pops the root table
return 0;
}

View File

@ -0,0 +1,58 @@
.. _embedding_debug_interface:
===============
Debug Interface
===============
The squirrel VM exposes a very simple debug interface that allows to easily built a full
featured debugger.
Through the functions sq_setdebughook and sq_setnativedebughook is possible in fact to set a callback function that
will be called every time the VM executes an new line of a script or if a function get
called/returns. The callback will pass as argument the current line the current source and the
current function name (if any).::
SQUIRREL_API void sq_setdebughook(HSQUIRRELVM v);
or ::
SQUIRREL_API void sq_setnativedebughook(HSQUIRRELVM v,SQDEBUGHOOK hook);
The following code shows how a debug hook could look like(obviously is possible to
implement this function in C as well). ::
function debughook(event_type,sourcefile,line,funcname)
{
local fname=funcname?funcname:"unknown";
local srcfile=sourcefile?sourcefile:"unknown"
switch (event_type) {
case 'l': //called every line(that contains some code)
::print("LINE line [" + line + "] func [" + fname + "]");
::print("file [" + srcfile + "]\n");
break;
case 'c': //called when a function has been called
::print("LINE line [" + line + "] func [" + fname + "]");
::print("file [" + srcfile + "]\n");
break;
case 'r': //called when a function returns
::print("LINE line [" + line + "] func [" + fname + "]");
::print("file [" + srcfile + "]\n");
break;
}
}
The parameter *event_type* can be 'l' ,'c' or 'r' ; a hook with a 'l' event is called for each line that
gets executed, 'c' every time a function gets called and 'r' every time a function returns.
A full-featured debugger always allows displaying local variables and calls stack.
The call stack information are retrieved through sq_getstackinfos()::
SQInteger sq_stackinfos(HSQUIRRELVM v,SQInteger level,SQStackInfos *si);
While the local variables info through sq_getlocal()::
SQInteger sq_getlocal(HSQUIRRELVM v,SQUnsignedInteger level,SQUnsignedInteger nseq);
In order to receive line callbacks the scripts have to be compiled with debug infos enabled
this is done through sq_enabledebuginfo(); ::
void sq_enabledebuginfo(HSQUIRRELVM v, SQInteger debuginfo);

View File

@ -0,0 +1,16 @@
.. _embedding_error_convetions:
========================
Error Conventions
========================
.. index::
single: Error Conventions
Most of the functions in the API return a SQRESULT value; SQRESULT indicates if a
function completed successfully or not.
The macros SQ_SUCCEEDED() and SQ_FAILED() are used to test the result of a function.::
if(SQ_FAILED(sq_getstring(v,-1,&s)))
printf("getstring failed");

View File

@ -0,0 +1,28 @@
.. _embedding_memory_management:
========================
Memory Management
========================
.. index:: single: Memory Management
Squirrel uses reference counting (RC) as primary system for memory management;
however, the virtual machine (VM) has an auxiliary
mark and sweep garbage collector that can be invoked on demand.
There are 2 possible compile time options:
* The default configuration consists in RC plus a mark and sweep garbage collector.
The host program can call the function sq_collectgarbage() and perform a garbage collection cycle
during the program execution. The garbage collector isn't invoked by the VM and has to
be explicitly called by the host program.
* The second a situation consists in RC only(define NO_GARBAGE_COLLECTOR); in this case is impossible for
the VM to detect reference cycles, so is the programmer that has to solve them explicitly in order to
avoid memory leaks.
The only advantage introduced by the second option is that saves 2 additional
pointers that have to be stored for each object in the default configuration with
garbage collector(8 bytes for 32 bits systems).
The types involved are: tables, arrays, functions, threads, userdata and generators; all other
types are untouched. These options do not affect execution speed.

View File

@ -0,0 +1,21 @@
.. embedding_references_from_c:
========================================================
Mantaining references to Squirrel values from the C API
========================================================
Squirrel allows to reference values through the C API; the function sq_getstackobj() gets
a handle to a squirrel object(any type). The object handle can be used to control the lifetime
of an object by adding or removing references to it( see sq_addref() and sq_release()).
The object can be also re-pushed in the VM stack using sq_pushobject().::
HSQOBJECT obj;
sq_resetobject(&obj); //initialize the handle
sq_getstackobj(v,-2,&obj); //retrieve an object handle from the pos -2
sq_addref(v,&obj); //adds a reference to the object
... //do stuff
sq_pushobject(v,obj); //push the object in the stack
sq_release(v,&obj); //relese the object

View File

@ -0,0 +1,17 @@
.. _embedding_runtime_error_handling:
======================
Runtime error handling
======================
When an exception is not handled by Squirrel code with a try/catch statement, a runtime
error is raised and the execution of the current program is interrupted. It is possible to
set a call back function to intercept the runtime error from the host program; this is
useful to show meaningful errors to the script writer and for implementing visual
debuggers.
The following API call pops a Squirrel function from the stack and sets it as error handler.::
SQUIRREL_API void sq_seterrorhandler(HSQUIRRELVM v);
The error handler is called with 2 parameters, an environment object (this) and a object.
The object can be any squirrel type.

View File

@ -0,0 +1,70 @@
.. _embedding_tables_and_arrays_manipulation:
==============================
Tables and arrays manipulation
==============================
A new table is created calling sq_newtable, this function pushes a new table in the stack.::
void sq_newtable(HSQUIRRELVM v);
To create a new slot::
SQRESULT sq_newslot(HSQUIRRELVM v,SQInteger idx,SQBool bstatic);
To set or get the table delegate::
SQRESULT sq_setdelegate(HSQUIRRELVM v,SQInteger idx);
SQRESULT sq_getdelegate(HSQUIRRELVM v,SQInteger idx);
A new array is created calling sq_newarray, the function pushes a new array in the
stack; if the parameters size is bigger than 0 the elements are initialized to null.::
void sq_newarray (HSQUIRRELVM v,SQInteger size);
To append a value to the back of the array::
SQRESULT sq_arrayappend(HSQUIRRELVM v,SQInteger idx);
To remove a value from the back of the array::
SQRESULT sq_arraypop(HSQUIRRELVM v,SQInteger idx,SQInteger pushval);
To resize the array::
SQRESULT sq_arrayresize(HSQUIRRELVM v,SQInteger idx,SQInteger newsize);
To retrieve the size of a table or an array you must use sq_getsize()::
SQInteger sq_getsize(HSQUIRRELVM v,SQInteger idx);
To set a value in an array or table::
SQRESULT sq_set(HSQUIRRELVM v,SQInteger idx);
To get a value from an array or table::
SQRESULT sq_get(HSQUIRRELVM v,SQInteger idx);
To get or set a value from a table without employing delegation::
SQRESULT sq_rawget(HSQUIRRELVM v,SQInteger idx);
SQRESULT sq_rawset(HSQUIRRELVM v,SQInteger idx);
To iterate a table or an array::
SQRESULT sq_next(HSQUIRRELVM v,SQInteger idx);
Here an example of how to perform an iteration: ::
//push your table/array here
sq_pushnull(v) //null iterator
while(SQ_SUCCEEDED(sq_next(v,-2)))
{
//here -1 is the value and -2 is the key
sq_pop(v,2); //pops key and val before the nex iteration
}
sq_pop(v,1); //pops the null iterator

View File

@ -0,0 +1,14 @@
.. _embedding_the_registry_table:
==================
The registry table
==================
The registry table is an hidden table shared between vm and all his thread(friend vms).
This table is accessible only through the C API and is meant to be an utility structure
for native C library implementation.
For instance the sqstdlib(squirrel standard library)uses it to store configuration and shared objects
delegates.
The registry is accessible through the API call *sq_pushregistrytable()*.::
void sq_pushregistrytable(HSQUIRRELVM v);

View File

@ -0,0 +1,104 @@
.. _embedding_the_stack:
==========
The Stack
==========
Squirrel exchanges values with the virtual machine through a stack. This mechanism has
been inherited from the language Lua.
For instance to call a Squirrel function from C it is necessary to push the function and the
arguments in the stack and then invoke the function; also when Squirrel calls a C
function the parameters will be in the stack as well.
-------------
Stack indexes
-------------
Many API functions can arbitrarily refer to any element in the stack through an index.
The stack indexes follow those conventions:
* 1 is the stack base
* Negative indexes are considered an offset from top of the stack. For instance -1 isthe top of the stack.
* 0 is an invalid index
Here an example (let's pretend that this table is the VM stack)
+------------+--------------------+--------------------+
| **STACK** | **positive index** | **negative index** |
+============+====================+====================+
| "test" | 4 | -1(top) |
+------------+--------------------+--------------------+
| 1 | 3 | -2 |
+------------+--------------------+--------------------+
| 0.5 | 2 | -3 |
+------------+--------------------+--------------------+
| "foo" | 1(base) | -4 |
+------------+--------------------+--------------------+
In this case, the function *sq_gettop* would return 4;
------------------
Stack manipulation
------------------
The API offers several functions to push and retrieve data from the Squirrel stack.
To push a value that is already present in the stack in the top position::
void sq_push(HSQUIRRELVM v,SQInteger idx);
To pop an arbitrary number of elements::
void sq_pop(HSQUIRRELVM v,SQInteger nelemstopop);
To remove an element from the stack::
void sq_remove(HSQUIRRELVM v,SQInteger idx);
To retrieve the top index (and size) of the current
virtual stack you must call *sq_gettop* ::
SQInteger sq_gettop(HSQUIRRELVM v);
To force the stack to a certain size you can call *sq_settop* ::
void sq_settop(HSQUIRRELVM v,SQInteger newtop);
If the newtop is bigger than the previous one, the new positions in the stack will be
filled with null values.
The following function pushes a C value into the stack::
void sq_pushstring(HSQUIRRELVM v,const SQChar *s,SQInteger len);
void sq_pushfloat(HSQUIRRELVM v,SQFloat f);
void sq_pushinteger(HSQUIRRELVM v,SQInteger n);
void sq_pushuserpointer(HSQUIRRELVM v,SQUserPointer p);
void sq_pushbool(HSQUIRRELVM v,SQBool b);
this function pushes a null into the stack::
void sq_pushnull(HSQUIRRELVM v);
returns the type of the value in a arbitrary position in the stack::
SQObjectType sq_gettype(HSQUIRRELVM v,SQInteger idx);
the result can be one of the following values: ::
OT_NULL,OT_INTEGER,OT_FLOAT,OT_STRING,OT_TABLE,OT_ARRAY,OT_USERDATA,
OT_CLOSURE,OT_NATIVECLOSURE,OT_GENERATOR,OT_USERPOINTER,OT_BOOL,OT_INSTANCE,OT_CLASS,OT_WEAKREF
The following functions convert a squirrel value in the stack to a C value::
SQRESULT sq_getstring(HSQUIRRELVM v,SQInteger idx,const SQChar **c);
SQRESULT sq_getstringandsize(HSQUIRRELVM v,SQInteger idx,const SQChar **c,SQInteger size);
SQRESULT sq_getinteger(HSQUIRRELVM v,SQInteger idx,SQInteger *i);
SQRESULT sq_getfloat(HSQUIRRELVM v,SQInteger idx,SQFloat *f);
SQRESULT sq_getuserpointer(HSQUIRRELVM v,SQInteger idx,SQUserPointer *p);
SQRESULT sq_getuserdata(HSQUIRRELVM v,SQInteger idx,SQUserPointer *p,SQUserPointer *typetag);
SQRESULT sq_getbool(HSQUIRRELVM v,SQInteger idx,SQBool *p);
The function sq_cmp compares 2 values from the stack and returns their relation (like strcmp() in ANSI C).::
SQInteger sq_cmp(HSQUIRRELVM v);

View File

@ -0,0 +1,33 @@
.. _embedding_userdata_and_userpointers:
=========================
Userdata and UserPointers
=========================
Squirrel allows the host application put arbitrary data chunks into a Squirrel value, this is
possible through the data type userdata.::
SQUserPointer sq_newuserdata(HSQUIRRELVM v,SQUnsignedInteger size);
When the function *sq_newuserdata* is called, Squirrel allocates a new userdata with the
specified size, returns a pointer to his payload buffer and push the object in the stack; at
this point the application can do whatever it want with this memory chunk, the VM will
automatically take cake of the memory deallocation like for every other built-in type.
A userdata can be passed to a function or stored in a table slot. By default Squirrel
cannot manipulate directly userdata; however is possible to assign a delegate to it and
define a behavior like it would be a table.
Because the application would want to do something with the data stored in a userdata
object when it get deleted, is possible to assign a callback that will be called by the VM
just before deleting a certain userdata.
This is done through the API call *sq_setreleasehook*.::
typedef SQInteger (*SQRELEASEHOOK)(SQUserPointer,SQInteger size);
void sq_setreleasehook(HSQUIRRELVM v,SQInteger idx,SQRELEASEHOOK hook);
Another kind of userdata is the userpointer; this type is not a memory chunk like the
normal userdata, but just a 'void*' pointer. It cannot have a delegate and is passed by
value, so pushing a userpointer doesn't cause any memory allocation.::
void sq_pushuserpointer(HSQUIRRELVM v,SQUserPointer p);

View File

@ -0,0 +1,21 @@
.. _embedding_vm_initialization:
==============================
Virtual Machine Initialization
==============================
The first thing that a host application has to do, is create a virtual machine.
The host application can create any number of virtual machines through the function
*sq_open()*.
Every single VM that was created using *sq_open()* has to be released with the function *sq_close()* when it is no
longer needed.::
int main(int argc, char* argv[])
{
HSQUIRRELVM v;
v = sq_open(1024); //creates a VM with initial stack size 1024
//do some stuff with squirrel here
sq_close(v);
}

View File

@ -0,0 +1,29 @@
.. _embedding_squirrel:
***************************
Embedding Squirrel
***************************
*This section describes how to embed Squirrel in a host application,
C language knowledge is required to understand this part of the manual.*
Because of his nature of extension language, Squirrel's compiler and virtual machine
are implemented as C library. The library exposes a set of functions to compile scripts,
call functions, manipulate data and extend the virtual machine.
All declarations needed for embedding the language in an application are in the header file 'squirrel.h'.
.. toctree::
embedding/memory_management.rst
embedding/build_configuration.rst
embedding/error_conventions.rst
embedding/vm_initialization.rst
embedding/the_stack.rst
embedding/runtime_error_handling.rst
embedding/compiling_a_script.rst
embedding/calling_a_function.rst
embedding/creating_a_c_function.rst
embedding/tables_and_arrays_manipulation.rst
embedding/userdata_and_userpointers.rst
embedding/the_registry_table.rst
embedding/references_from_c.rst
embedding/debug_interface.rst

View File

@ -0,0 +1,34 @@
.. _reference:
#################################
Squirrel 3.1 Reference Manual
#################################
Copyright (c) 2003-2016 Alberto Demichelis
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
.. toctree::
:maxdepth: 3
:numbered:
introduction.rst
language.rst
embedding_squirrel.rst
api_reference.rst

Some files were not shown because too many files have changed in this diff Show More