Merge pull request #321 from z33ky/dangling-vscript-vector

Prevent return of dangling Vector/QAngle to VScript
This commit is contained in:
Blixibon 2025-02-25 14:37:13 -06:00 committed by GitHub
commit a5236830fc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 301 additions and 300 deletions

View File

@ -16,6 +16,10 @@
#include "saverestore_utlvector.h"
#include "dt_utlvector_send.h"
#ifdef MAPBASE_VSCRIPT
#include "mapbase/vscript_funcs_shared.h"
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
@ -471,7 +475,8 @@ void CAnimationLayer::DispatchAnimEvents( CBaseAnimating *eventHandler, CBaseAni
}
#ifdef MAPBASE_VSCRIPT
if (eventHandler->m_ScriptScope.IsInitialized() && eventHandler->ScriptHookHandleAnimEvent( &event ) == false)
scriptanimevent_t wrapper( event );
if (eventHandler->m_ScriptScope.IsInitialized() && !eventHandler->ScriptHookHandleAnimEvent( wrapper ))
continue;
#endif

View File

@ -1261,7 +1261,8 @@ void CBaseAnimating::DispatchAnimEvents ( CBaseAnimating *eventHandler )
}
#ifdef MAPBASE_VSCRIPT
if (eventHandler->ScriptHookHandleAnimEvent( &event ) == false)
scriptanimevent_t wrapper( event );
if (!eventHandler->ScriptHookHandleAnimEvent( wrapper ))
continue;
#endif
@ -1299,11 +1300,11 @@ void CBaseAnimating::DispatchAnimEvents ( CBaseAnimating *eventHandler )
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CBaseAnimating::ScriptHookHandleAnimEvent( animevent_t *pEvent )
bool CBaseAnimating::ScriptHookHandleAnimEvent( scriptanimevent_t &event )
{
if (m_ScriptScope.IsInitialized() && g_Hook_HandleAnimEvent.CanRunInScope(m_ScriptScope))
{
HSCRIPT hEvent = g_pScriptVM->RegisterInstance( reinterpret_cast<scriptanimevent_t*>(pEvent) );
HSCRIPT hEvent = g_pScriptVM->RegisterInstance( &event );
// event
ScriptVariant_t args[] = { hEvent };

View File

@ -16,6 +16,9 @@
#include "datacache/idatacache.h"
#include "tier0/threadtools.h"
#ifdef MAPBASE_VSCRIPT
struct scriptanimevent_t;
#endif
struct animevent_t;
struct matrix3x4_t;
@ -146,7 +149,7 @@ public:
virtual void DispatchAnimEvents ( CBaseAnimating *eventHandler ); // Handle events that have happend since last time called up until X seconds into the future
virtual void HandleAnimEvent( animevent_t *pEvent );
#ifdef MAPBASE_VSCRIPT
bool ScriptHookHandleAnimEvent( animevent_t *pEvent );
bool ScriptHookHandleAnimEvent( scriptanimevent_t &event );
#endif
int LookupPoseParameter( CStudioHdr *pStudioHdr, const char *szName );

View File

@ -2645,16 +2645,19 @@ Vector CProtoSniper::DesiredBodyTarget( CBaseEntity *pTarget )
{
// By default, aim for the center
Vector vecTarget = pTarget->WorldSpaceCenter();
const Vector vecBulletOrigin = GetBulletOrigin();
#ifdef MAPBASE_VSCRIPT
if (m_ScriptScope.IsInitialized() && g_Hook_GetActualShootPosition.CanRunInScope(m_ScriptScope))
if ( m_ScriptScope.IsInitialized() && g_Hook_GetActualShootPosition.CanRunInScope( m_ScriptScope ) )
{
ScriptVariant_t functionReturn;
ScriptVariant_t args[] = { GetBulletOrigin(), ToHScript( pTarget ) };
if (g_Hook_GetActualShootPosition.Call( m_ScriptScope, &functionReturn, args ))
ScriptVariant_t args[] = { vecBulletOrigin, ToHScript( pTarget ) };
if ( g_Hook_GetActualShootPosition.Call( m_ScriptScope, &functionReturn, args ) )
{
if (functionReturn.m_type == FIELD_VECTOR && functionReturn.m_pVector->LengthSqr() != 0.0f)
if ( functionReturn.m_type == FIELD_VECTOR && functionReturn.m_pVector->LengthSqr() != 0.0f )
{
return *functionReturn.m_pVector;
}
}
}
#endif
@ -2682,12 +2685,12 @@ Vector CProtoSniper::DesiredBodyTarget( CBaseEntity *pTarget )
{
if( flTimeSinceLastMiss > 0.0f && flTimeSinceLastMiss < 4.0f && hl2_episodic.GetBool() )
{
vecTarget = pTarget->BodyTarget( GetBulletOrigin(), false );
vecTarget = pTarget->BodyTarget( vecBulletOrigin, false );
}
else
{
// Shoot zombies in the headcrab
vecTarget = pTarget->HeadTarget( GetBulletOrigin() );
vecTarget = pTarget->HeadTarget( vecBulletOrigin );
}
}
else if( pTarget->Classify() == CLASS_ANTLION )

View File

@ -357,7 +357,8 @@ void RegisterSharedScriptConstants()
ScriptRegisterConstant( g_pScriptVM, ROPE_NO_GRAVITY, "Disable gravity on this rope. (for use in rope flags)" );
ScriptRegisterConstant( g_pScriptVM, ROPE_NUMFLAGS, "The number of rope flags recognized by the game." );
ScriptRegisterConstantNamed( g_pScriptVM, Vector( ROPE_GRAVITY ), "ROPE_GRAVITY", "Default rope gravity vector." );
static Vector vecRopeGravity( ROPE_GRAVITY );
ScriptRegisterConstantNamed( g_pScriptVM, vecRopeGravity, "ROPE_GRAVITY", "Default rope gravity vector." );
//
// Sounds

View File

@ -532,7 +532,7 @@ bool CAnimEventTInstanceHelper::Get( void *p, const char *pszKey, ScriptVariant_
{
DevWarning( "VScript animevent_t.%s: animevent_t metamethod members are deprecated! Use 'script_help animevent_t' to see the correct functions.\n", pszKey );
animevent_t *ani = ((animevent_t *)p);
animevent_t *ani = &((scriptanimevent_t *)p)->event;
if (FStrEq( pszKey, "event" ))
variant = ani->event;
else if (FStrEq( pszKey, "options" ))
@ -555,18 +555,28 @@ bool CAnimEventTInstanceHelper::Set( void *p, const char *pszKey, ScriptVariant_
{
DevWarning( "VScript animevent_t.%s: animevent_t metamethod members are deprecated! Use 'script_help animevent_t' to see the correct functions.\n", pszKey );
animevent_t *ani = ((animevent_t *)p);
scriptanimevent_t *script_ani = ((scriptanimevent_t *)p);
animevent_t *ani = &script_ani->event;
if (FStrEq( pszKey, "event" ))
ani->event = variant;
{
return variant.AssignTo( &ani->event );
}
else if (FStrEq( pszKey, "options" ))
ani->options = variant;
{
char *szOptions;
if (!variant.AssignTo( &szOptions ))
{
return false;
}
script_ani->SetOptions( szOptions );
}
else if (FStrEq( pszKey, "cycle" ))
ani->cycle = variant;
return variant.AssignTo( &ani->cycle );
else if (FStrEq( pszKey, "eventtime" ))
ani->eventtime = variant;
return variant.AssignTo( &ani->eventtime );
else if (FStrEq( pszKey, "type" ))
ani->type = variant;
else if (FStrEq( pszKey, "source" ))
return variant.AssignTo( &ani->type );
else if (FStrEq( pszKey, "source" ) && variant.m_type == FIELD_HSCRIPT)
{
CBaseEntity *pEnt = ToEnt( variant.m_hScript );
if (pEnt)

View File

@ -172,30 +172,47 @@ private:
//-----------------------------------------------------------------------------
// Exposes animevent_t to VScript
//-----------------------------------------------------------------------------
struct scriptanimevent_t : public animevent_t
struct scriptanimevent_t
{
int GetEvent() { return event; }
void SetEvent( int nEvent ) { event = nEvent; }
friend class CAnimEventTInstanceHelper;
const char *GetOptions() { return options; }
void SetOptions( const char *pOptions ) { options = pOptions; }
public:
scriptanimevent_t( animevent_t &event ) : event( event ), options( NULL ) { }
~scriptanimevent_t( ) { delete[] options; }
float GetCycle() { return cycle; }
void SetCycle( float flCycle ) { cycle = flCycle; }
int GetEvent() { return event.event; }
void SetEvent( int nEvent ) { event.event = nEvent; }
float GetEventTime() { return eventtime; }
void SetEventTime( float flEventTime ) { eventtime = flEventTime; }
const char *GetOptions() { return event.options; }
void SetOptions( const char *pOptions )
{
size_t len = strlen( pOptions );
delete[] options;
event.options = options = new char[len + 1];
memcpy( options, pOptions, len + 1 );
}
int GetType() { return type; }
void SetType( int nType ) { eventtime = type; }
float GetCycle() { return event.cycle; }
void SetCycle( float flCycle ) { event.cycle = flCycle; }
HSCRIPT GetSource() { return ToHScript( pSource ); }
float GetEventTime() { return event.eventtime; }
void SetEventTime( float flEventTime ) { event.eventtime = flEventTime; }
int GetType() { return event.type; }
void SetType( int nType ) { event.type = nType; }
HSCRIPT GetSource() { return ToHScript( event.pSource ); }
void SetSource( HSCRIPT hSource )
{
CBaseEntity *pEnt = ToEnt( hSource );
if (pEnt)
pSource = pEnt->GetBaseAnimating();
event.pSource = pEnt->GetBaseAnimating();
}
private:
animevent_t &event;
// storage for ScriptVariant_t string, which may be temporary
char *options;
};
class CAnimEventTInstanceHelper : public IScriptInstanceHelper

View File

@ -300,7 +300,8 @@ enum ScriptFuncBindingFlags_t
SF_MEMBER_FUNC = 0x01,
};
typedef bool (*ScriptBindingFunc_t)( void *pFunction, void *pContext, ScriptVariant_t *pArguments, int nArguments, ScriptVariant_t *pReturn );
union ScriptVariantTemporaryStorage_t;
typedef bool (*ScriptBindingFunc_t)( void *pFunction, void *pContext, ScriptVariant_t *pArguments, int nArguments, ScriptVariant_t *pReturn, ScriptVariantTemporaryStorage_t &temporaryReturnStorage );
struct ScriptFunctionBinding_t
{
@ -321,11 +322,6 @@ public:
#ifdef MAPBASE_VSCRIPT
virtual bool Get( void *p, const char *pszKey, ScriptVariant_t &variant ) { return false; }
virtual bool Set( void *p, const char *pszKey, ScriptVariant_t &variant ) { return false; }
virtual ScriptVariant_t *Add( void *p, ScriptVariant_t &variant ) { return NULL; }
virtual ScriptVariant_t *Subtract( void *p, ScriptVariant_t &variant ) { return NULL; }
virtual ScriptVariant_t *Multiply( void *p, ScriptVariant_t &variant ) { return NULL; }
virtual ScriptVariant_t *Divide( void *p, ScriptVariant_t &variant ) { return NULL; }
#endif
};
@ -390,13 +386,17 @@ struct ScriptVariant_t
ScriptVariant_t( bool val ) : m_flags( 0 ), m_type( FIELD_BOOLEAN ) { m_bool = val; }
ScriptVariant_t( HSCRIPT val ) : m_flags( 0 ), m_type( FIELD_HSCRIPT ) { m_hScript = val; }
ScriptVariant_t( const Vector &val, bool bCopy = false ) : m_flags( 0 ), m_type( FIELD_VECTOR ) { if ( !bCopy ) { m_pVector = &val; } else { m_pVector = new Vector( val ); m_flags |= SV_FREE; } }
ScriptVariant_t( const Vector *val, bool bCopy = false ) : m_flags( 0 ), m_type( FIELD_VECTOR ) { if ( !bCopy ) { m_pVector = val; } else { m_pVector = new Vector( *val ); m_flags |= SV_FREE; } }
ScriptVariant_t( const char *val , bool bCopy = false ) : m_flags( 0 ), m_type( FIELD_CSTRING ) { if ( !bCopy ) { m_pszString = val; } else { m_pszString = strdup( val ); m_flags |= SV_FREE; } }
ScriptVariant_t( const Vector &val ) : m_flags( 0 ), m_type( FIELD_VECTOR ) { m_pVector = &val; }
ScriptVariant_t( const Vector *val ) : ScriptVariant_t( *val ) { }
ScriptVariant_t( const char *val ) : m_flags( 0 ), m_type( FIELD_CSTRING ) { m_pszString = val; }
#ifdef MAPBASE_VSCRIPT
ScriptVariant_t( const QAngle &val, bool bCopy = false ) : m_flags( 0 ), m_type( FIELD_VECTOR ) { if ( !bCopy ) { m_pAngle = &val; } else { m_pAngle = new QAngle( val ); m_flags |= SV_FREE; } }
ScriptVariant_t( const QAngle *val, bool bCopy = false ) : m_flags( 0 ), m_type( FIELD_VECTOR ) { if ( !bCopy ) { m_pAngle = val; } else { m_pAngle = new QAngle( *val ); m_flags |= SV_FREE; } }
ScriptVariant_t( const QAngle &val ) : m_flags( 0 ), m_type( FIELD_VECTOR ) { m_pAngle = &val; }
ScriptVariant_t( const QAngle *val ) : ScriptVariant_t( *val ) { }
ScriptVariant_t( Vector &&val ) = delete;
ScriptVariant_t( QAngle &&val ) = delete;
#endif
bool IsNull() const { return (m_type == FIELD_VOID ); }
@ -404,74 +404,41 @@ struct ScriptVariant_t
operator int() const { Assert( m_type == FIELD_INTEGER ); return m_int; }
operator float() const { Assert( m_type == FIELD_FLOAT ); return m_float; }
operator const char *() const { Assert( m_type == FIELD_CSTRING ); return ( m_pszString ) ? m_pszString : ""; }
operator const Vector &() const { Assert( m_type == FIELD_VECTOR ); static Vector vecNull(0, 0, 0); return (m_pVector) ? *m_pVector : vecNull; }
operator const Vector &() const { Assert( m_type == FIELD_VECTOR ); return (m_pVector) ? *m_pVector : vec3_origin; }
operator char() const { Assert( m_type == FIELD_CHARACTER ); return m_char; }
operator bool() const { Assert( m_type == FIELD_BOOLEAN ); return m_bool; }
operator HSCRIPT() const { Assert( m_type == FIELD_HSCRIPT ); return m_hScript; }
#ifdef MAPBASE_VSCRIPT
operator const QAngle &() const { Assert( m_type == FIELD_VECTOR ); static QAngle vecNull(0, 0, 0); return (m_pAngle) ? *m_pAngle : vecNull; }
operator const QAngle &() const { Assert( m_type == FIELD_VECTOR ); return (m_pAngle) ? *m_pAngle : vec3_angle; }
#endif
void operator=( int i ) { m_type = FIELD_INTEGER; m_int = i; }
void operator=( float f ) { m_type = FIELD_FLOAT; m_float = f; }
void operator=( double f ) { m_type = FIELD_FLOAT; m_float = (float)f; }
void operator=( const Vector &vec ) { m_type = FIELD_VECTOR; m_pVector = &vec; }
void operator=( const Vector *vec ) { m_type = FIELD_VECTOR; m_pVector = vec; }
void operator=( const char *psz ) { m_type = FIELD_CSTRING; m_pszString = psz; }
void operator=( char c ) { m_type = FIELD_CHARACTER; m_char = c; }
void operator=( bool b ) { m_type = FIELD_BOOLEAN; m_bool = b; }
void operator=( HSCRIPT h ) { m_type = FIELD_HSCRIPT; m_hScript = h; }
void operator=( int i ) { m_type = FIELD_INTEGER; m_flags = 0; m_int = i; }
void operator=( float f ) { m_type = FIELD_FLOAT; m_flags = 0; m_float = f; }
void operator=( double f ) { m_type = FIELD_FLOAT; m_flags = 0; m_float = (float)f; }
void operator=( const Vector &vec ) { m_type = FIELD_VECTOR; m_flags = 0; m_pVector = &vec; }
void operator=( const Vector *vec ) { m_type = FIELD_VECTOR; m_flags = 0; m_pVector = vec; }
void operator=( const char *psz ) { m_type = FIELD_CSTRING; m_flags = 0; m_pszString = psz; }
void operator=( char c ) { m_type = FIELD_CHARACTER; m_flags = 0; m_char = c; }
void operator=( bool b ) { m_type = FIELD_BOOLEAN; m_flags = 0; m_bool = b; }
void operator=( HSCRIPT h ) { m_type = FIELD_HSCRIPT; m_flags = 0; m_hScript = h; }
#ifdef MAPBASE_VSCRIPT
void operator=( const QAngle &vec ) { m_type = FIELD_VECTOR; m_pAngle = &vec; }
void operator=( const QAngle *vec ) { m_type = FIELD_VECTOR; m_pAngle = vec; }
void operator=( const QAngle &ang ) { m_type = FIELD_VECTOR; m_flags = 0; m_pAngle = &ang; }
void operator=( const QAngle *ang ) { m_type = FIELD_VECTOR; m_flags = 0; m_pAngle = ang; }
void operator=( Vector &&vec ) = delete;
void operator=( QAngle &&ang ) = delete;
#endif
void Free() { if ( ( m_flags & SV_FREE ) && ( m_type == FIELD_HSCRIPT || m_type == FIELD_VECTOR || m_type == FIELD_CSTRING ) ) delete m_pszString; } // Generally only needed for return results
template <typename T>
T Get()
void Free()
{
T value;
AssignTo( &value );
return value;
}
template <typename T>
bool AssignTo( T *pDest )
{
ScriptDataType_t destType = ScriptDeduceType( T );
if ( destType == FIELD_TYPEUNKNOWN )
// Generally only needed for return results
if ( ! ( m_flags & SV_FREE ) )
{
DevWarning( "Unable to convert script variant to unknown type\n" );
}
if ( destType == m_type )
{
*pDest = *this;
return true;
return;
}
if ( m_type != FIELD_VECTOR && m_type != FIELD_CSTRING && destType != FIELD_VECTOR && destType != FIELD_CSTRING )
{
switch ( m_type )
{
case FIELD_VOID: *pDest = 0; break;
case FIELD_INTEGER: *pDest = m_int; return true;
case FIELD_FLOAT: *pDest = m_float; return true;
case FIELD_CHARACTER: *pDest = m_char; return true;
case FIELD_BOOLEAN: *pDest = m_bool; return true;
case FIELD_HSCRIPT: *pDest = m_hScript; return true;
}
}
else
{
DevWarning( "No free conversion of %s script variant to %s right now\n",
ScriptFieldTypeName( m_type ), ScriptFieldTypeName<T>() );
if ( destType != FIELD_VECTOR )
{
*pDest = 0;
}
}
return false;
AssertMsg( m_type == FIELD_CSTRING || m_type == FIELD_VECTOR, "Don't know how to free script variant of type %d", m_type );
free( (void*)m_pszString );
}
bool AssignTo( float *pDest )
@ -526,25 +493,38 @@ struct ScriptVariant_t
bool AssignTo( ScriptVariant_t *pDest )
{
pDest->Free();
pDest->m_type = m_type;
if ( m_type == FIELD_VECTOR )
if ( m_flags & SV_FREE )
{
pDest->m_pVector = new Vector;
((Vector *)(pDest->m_pVector))->Init( m_pVector->x, m_pVector->y, m_pVector->z );
pDest->m_flags |= SV_FREE;
}
else if ( m_type == FIELD_CSTRING )
{
pDest->m_pszString = strdup( m_pszString );
pDest->m_flags |= SV_FREE;
if ( m_type == FIELD_VECTOR )
{
pDest->m_pVector = (Vector*)malloc( sizeof( Vector ) );
pDest->EmplaceAllocedVector( *m_pVector );
m_flags |= SV_FREE;
}
else if ( m_type == FIELD_CSTRING )
{
pDest->m_pszString = strdup( m_pszString );
pDest->m_flags |= SV_FREE;
}
else
{
Assert( false );
pDest->m_int = m_int;
pDest->m_flags &= ~SV_FREE;
}
}
else
{
pDest->m_int = m_int;
pDest->m_flags &= ~SV_FREE;
}
return false;
}
void EmplaceAllocedVector( const Vector &vec );
union
{
int m_int;
@ -566,8 +546,25 @@ struct ScriptVariant_t
private:
};
#include "tier0/memdbgoff.h"
inline void ScriptVariant_t::EmplaceAllocedVector( const Vector &vec )
{
new ( (Vector*)m_pVector ) Vector( vec );
}
#include "tier0/memdbgon.h"
#define SCRIPT_VARIANT_NULL ScriptVariant_t()
union ScriptVariantTemporaryStorage_t
{
// members must be initialized via placement-new
ScriptVariantTemporaryStorage_t() { }
// members must have trivial destructor, since no destructor will be invoked
Vector m_vec;
QAngle m_ang;
};
#ifdef MAPBASE_VSCRIPT
//---------------------------------------------------------
struct ScriptConstantBinding_t
@ -660,7 +657,7 @@ static inline int ToConstantVariant(int value)
// This is used for registering variants (particularly vectors) not tied to existing variables.
// The principal difference is that m_data is initted with bCopy set to true.
#define ScriptRegisterConstantFromTemp( pVM, constant, description ) ScriptRegisterConstantFromTempNamed( pVM, constant, #constant, description )
#define ScriptRegisterConstantFromTempNamed( pVM, constant, scriptName, description ) do { static ScriptConstantBinding_t binding; binding.m_pszScriptName = scriptName; binding.m_pszDescription = description; binding.m_data = ScriptVariant_t( constant, true ); pVM->RegisterConstant( &binding ); } while (0)
#define ScriptRegisterConstantFromTempNamed( pVM, constant, scriptName, description ) do { static const auto constantStorage = constant; static ScriptConstantBinding_t binding; binding.m_pszScriptName = scriptName; binding.m_pszDescription = description; binding.m_data = ScriptVariant_t( constantStorage ); pVM->RegisterConstant( &binding ); } while (0)
//-----------------------------------------------------------------------------
//

View File

@ -326,8 +326,8 @@ inline FUNCPTR_TYPE ScriptConvertFuncPtrFromVoid( void *p )
class CNonMemberScriptBinding##N \
{ \
public: \
static bool Call( void *pFunction, void *pContext, ScriptVariant_t *pArguments, int nArguments, ScriptVariant_t *pReturn ) \
{ \
static bool Call( void *pFunction, void *pContext, ScriptVariant_t *pArguments, int nArguments, ScriptVariant_t *pReturn, ScriptVariantTemporaryStorage_t &temporaryReturnStorage ) \
{ \
Assert( nArguments == N ); \
Assert( pReturn ); \
Assert( !pContext ); \
@ -337,17 +337,15 @@ inline FUNCPTR_TYPE ScriptConvertFuncPtrFromVoid( void *p )
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; \
} \
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 ) \
static bool Call( void *pFunction, void *pContext, ScriptVariant_t *pArguments, int nArguments, ScriptVariant_t *pReturn, ScriptVariantTemporaryStorage_t &temporaryReturnStorage ) \
{ \
Assert( nArguments == N ); \
Assert( !pReturn ); \
@ -362,12 +360,52 @@ inline FUNCPTR_TYPE ScriptConvertFuncPtrFromVoid( void *p )
} \
}; \
\
template <typename FUNC_TYPE FUNC_TEMPLATE_FUNC_PARAMS_##N> \
class CNonMemberScriptBinding##N<FUNC_TYPE, Vector FUNC_BASE_TEMPLATE_FUNC_PARAMS_PASSTHRU_##N> \
{ \
public: \
static bool Call( void *pFunction, void *pContext, ScriptVariant_t *pArguments, int nArguments, ScriptVariant_t *pReturn, ScriptVariantTemporaryStorage_t &temporaryReturnStorage ) \
{ \
Assert( nArguments == N ); \
Assert( pReturn ); \
Assert( !pContext ); \
\
if ( nArguments != N || !pReturn || pContext ) \
{ \
return false; \
} \
new ( &temporaryReturnStorage.m_vec ) Vector( ((FUNC_TYPE)pFunction)( SCRIPT_BINDING_ARGS_##N ) ); \
*pReturn = temporaryReturnStorage.m_vec; \
return true; \
} \
}; \
\
template <typename FUNC_TYPE FUNC_TEMPLATE_FUNC_PARAMS_##N> \
class CNonMemberScriptBinding##N<FUNC_TYPE, QAngle FUNC_BASE_TEMPLATE_FUNC_PARAMS_PASSTHRU_##N> \
{ \
public: \
static bool Call( void *pFunction, void *pContext, ScriptVariant_t *pArguments, int nArguments, ScriptVariant_t *pReturn, ScriptVariantTemporaryStorage_t &temporaryReturnStorage ) \
{ \
Assert( nArguments == N ); \
Assert( pReturn ); \
Assert( !pContext ); \
\
if ( nArguments != N || !pReturn || pContext ) \
{ \
return false; \
} \
new ( &temporaryReturnStorage.m_ang ) QAngle( ((FUNC_TYPE)pFunction)( SCRIPT_BINDING_ARGS_##N ) ); \
*pReturn = temporaryReturnStorage.m_ang; \
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 ) \
{ \
static bool Call( void *pFunction, void *pContext, ScriptVariant_t *pArguments, int nArguments, ScriptVariant_t *pReturn, ScriptVariantTemporaryStorage_t &temporaryReturnStorage ) \
{ \
Assert( nArguments == N ); \
Assert( pReturn ); \
Assert( pContext ); \
@ -377,17 +415,15 @@ inline FUNCPTR_TYPE ScriptConvertFuncPtrFromVoid( void *p )
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; \
} \
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 ) \
static bool Call( void *pFunction, void *pContext, ScriptVariant_t *pArguments, int nArguments, ScriptVariant_t *pReturn, ScriptVariantTemporaryStorage_t &temporaryReturnStorage ) \
{ \
Assert( nArguments == N ); \
Assert( !pReturn ); \
@ -402,6 +438,46 @@ inline FUNCPTR_TYPE ScriptConvertFuncPtrFromVoid( void *p )
} \
}; \
\
template <class OBJECT_TYPE_PTR, typename FUNC_TYPE FUNC_TEMPLATE_FUNC_PARAMS_##N> \
class CMemberScriptBinding##N<OBJECT_TYPE_PTR, FUNC_TYPE, Vector FUNC_BASE_TEMPLATE_FUNC_PARAMS_PASSTHRU_##N> \
{ \
public: \
static bool Call( void *pFunction, void *pContext, ScriptVariant_t *pArguments, int nArguments, ScriptVariant_t *pReturn, ScriptVariantTemporaryStorage_t &temporaryReturnStorage ) \
{ \
Assert( nArguments == N ); \
Assert( pReturn ); \
Assert( pContext ); \
\
if ( nArguments != N || !pReturn || !pContext ) \
{ \
return false; \
} \
new ( &temporaryReturnStorage.m_vec ) Vector( (((OBJECT_TYPE_PTR)(pContext))->*ScriptConvertFuncPtrFromVoid<FUNC_TYPE>(pFunction))( SCRIPT_BINDING_ARGS_##N ) ); \
*pReturn = temporaryReturnStorage.m_vec; \
return true; \
} \
}; \
\
template <class OBJECT_TYPE_PTR, typename FUNC_TYPE FUNC_TEMPLATE_FUNC_PARAMS_##N> \
class CMemberScriptBinding##N<OBJECT_TYPE_PTR, FUNC_TYPE, QAngle FUNC_BASE_TEMPLATE_FUNC_PARAMS_PASSTHRU_##N> \
{ \
public: \
static bool Call( void *pFunction, void *pContext, ScriptVariant_t *pArguments, int nArguments, ScriptVariant_t *pReturn, ScriptVariantTemporaryStorage_t &temporaryReturnStorage ) \
{ \
Assert( nArguments == N ); \
Assert( pReturn ); \
Assert( pContext ); \
\
if ( nArguments != N || !pReturn || !pContext ) \
{ \
return false; \
} \
new ( &temporaryReturnStorage.m_ang ) QAngle( (((OBJECT_TYPE_PTR)(pContext))->*ScriptConvertFuncPtrFromVoid<FUNC_TYPE>(pFunction))( SCRIPT_BINDING_ARGS_##N ) ); \
*pReturn = temporaryReturnStorage.m_ang; \
return true; \
} \
}; \
\
template <typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N> \
inline ScriptBindingFunc_t ScriptCreateBinding(FUNCTION_RETTYPE (*pfnProxied)( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) ) \
{ \
@ -423,7 +499,11 @@ inline FUNCPTR_TYPE ScriptConvertFuncPtrFromVoid( void *p )
return &CMemberScriptBinding##N<OBJECT_TYPE_PTR, Func_t, FUNCTION_RETTYPE FUNC_BASE_TEMPLATE_FUNC_PARAMS_PASSTHRU_##N>::Call; \
}
//note: no memory is actually allocated in the functions that get defined,
// it merely uses placement-new for which we need to disable this
#include "tier0/memdbgoff.h"
FUNC_GENERATE_ALL( DEFINE_SCRIPT_BINDINGS );
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
//

View File

@ -439,13 +439,11 @@ bool CScriptColorInstanceHelper::Get( void *p, const char *pszKey, ScriptVariant
bool CScriptColorInstanceHelper::Set( void *p, const char *pszKey, ScriptVariant_t &variant )
{
Color *pClr = ((Color *)p);
if ( strlen(pszKey) == 1 )
int iVal;
if ( strlen(pszKey) == 1 && variant.AssignTo( &iVal ) )
{
int iVal;
variant.AssignTo( &iVal );
switch (pszKey[0])
{
// variant.AssignTo( &(*pClr)[0] );
case 'r':
(*pClr)[0] = iVal;
return true;

View File

@ -258,39 +258,18 @@ bool CScriptQuaternionInstanceHelper::Set( void *p, const char *pszKey, ScriptVa
switch (pszKey[0])
{
case 'x':
variant.AssignTo( &pQuat->x );
return true;
return variant.AssignTo( &pQuat->x );
case 'y':
variant.AssignTo( &pQuat->y );
return true;
return variant.AssignTo( &pQuat->y );
case 'z':
variant.AssignTo( &pQuat->z );
return true;
return variant.AssignTo( &pQuat->z );
case 'w':
variant.AssignTo( &pQuat->w );
return true;
return variant.AssignTo( &pQuat->w );
}
}
return false;
}
ScriptVariant_t *CScriptQuaternionInstanceHelper::Add( void *p, ScriptVariant_t &variant )
{
Quaternion *pQuat = ((Quaternion *)p);
float flAdd;
variant.AssignTo( &flAdd );
(*pQuat)[0] += flAdd;
(*pQuat)[1] += flAdd;
(*pQuat)[2] += flAdd;
(*pQuat)[3] += flAdd;
static ScriptVariant_t result;
result = (HSCRIPT)p;
return &result;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------

View File

@ -40,11 +40,6 @@ class CScriptQuaternionInstanceHelper : public IScriptInstanceHelper
bool Get( void *p, const char *pszKey, ScriptVariant_t &variant );
bool Set( void *p, const char *pszKey, ScriptVariant_t &variant );
ScriptVariant_t *Add( void *p, ScriptVariant_t &variant );
//ScriptVariant_t *Subtract( void *p, ScriptVariant_t &variant );
//ScriptVariant_t *Multiply( void *p, ScriptVariant_t &variant );
//ScriptVariant_t *Divide( void *p, ScriptVariant_t &variant );
};
inline Quaternion *ToQuaternion( HSCRIPT hQuat ) { return HScriptToClass<Quaternion>( hQuat ); }

View File

@ -1232,6 +1232,8 @@ bool getVariant(HSQUIRRELVM vm, SQInteger idx, ScriptVariant_t& variant)
{
case OT_NULL:
{
variant.Free();
variant.m_flags = 0;
// TODO: Should this be (HSCRIPT)nullptr
variant.m_type = FIELD_VOID;
return true;
@ -1243,6 +1245,7 @@ bool getVariant(HSQUIRRELVM vm, SQInteger idx, ScriptVariant_t& variant)
{
return false;
}
variant.Free();
variant = (int)val;
return true;
}
@ -1253,6 +1256,7 @@ bool getVariant(HSQUIRRELVM vm, SQInteger idx, ScriptVariant_t& variant)
{
return false;
}
variant.Free();
variant = (float)val;
return true;
}
@ -1263,6 +1267,7 @@ bool getVariant(HSQUIRRELVM vm, SQInteger idx, ScriptVariant_t& variant)
{
return false;
}
variant.Free();
variant = val ? true : false;
return true;
}
@ -1274,7 +1279,8 @@ bool getVariant(HSQUIRRELVM vm, SQInteger idx, ScriptVariant_t& variant)
{
return false;
}
char* buffer = new char[size + 1];
variant.Free();
char* buffer = (char*)malloc(size + 1);
V_memcpy(buffer, val, size);
buffer[size] = 0;
variant = buffer;
@ -1289,7 +1295,9 @@ bool getVariant(HSQUIRRELVM vm, SQInteger idx, ScriptVariant_t& variant)
tag == TYPETAG_VECTOR &&
SQ_SUCCEEDED(sq_getinstanceup(vm, idx, (SQUserPointer*)&v, TYPETAG_VECTOR)))
{
variant = new Vector(*v);
variant.Free();
variant = (Vector*)malloc(sizeof(Vector));
variant.EmplaceAllocedVector(*v);
variant.m_flags |= SV_FREE;
return true;
}
@ -1297,6 +1305,7 @@ bool getVariant(HSQUIRRELVM vm, SQInteger idx, ScriptVariant_t& variant)
}
default:
{
variant.Free();
HSQOBJECT* obj = new HSQOBJECT;
sq_resetobject(obj);
sq_getstackobj(vm, idx, obj);
@ -1423,29 +1432,46 @@ SQInteger function_stub(HSQUIRRELVM vm)
instance = ((ClassInstanceData*)self)->instance;
}
ScriptVariant_t retval;
ScriptVariant_t script_retval;
ScriptVariantTemporaryStorage_t script_retval_storage;
SquirrelVM* pSquirrelVM = (SquirrelVM*)sq_getsharedforeignptr(vm);
Assert(pSquirrelVM);
sq_resetobject(&pSquirrelVM->lastError_);
(*pFunc->m_pfnBinding)(pFunc->m_pFunction, instance, params.Base(), nargs,
pFunc->m_desc.m_ReturnType == FIELD_VOID ? nullptr : &retval);
bool call_success = (*pFunc->m_pfnBinding)(pFunc->m_pFunction, instance, params.Base(), nargs,
pFunc->m_desc.m_ReturnType == FIELD_VOID ? nullptr : &script_retval, script_retval_storage);
Assert(call_success);
(void)call_success;
SQInteger sq_retval;
if (!sq_isnull(pSquirrelVM->lastError_))
{
sq_pushobject(vm, pSquirrelVM->lastError_);
sq_resetobject(&pSquirrelVM->lastError_);
return sq_throwobject(vm);
sq_retval = sq_throwobject(vm);
}
else
{
Assert(script_retval.m_type == pFunc->m_desc.m_ReturnType);
if (pFunc->m_desc.m_ReturnType != FIELD_VOID)
{
PushVariant(vm, script_retval);
sq_retval = 1;
}
else
{
sq_retval = 0;
}
}
PushVariant(vm, retval);
// strings never get copied here, Vector and QAngle are stored in script_retval_storage
// everything else is stored inline, so there should be no memory to free
Assert(!(script_retval.m_flags & SV_FREE));
if (retval.m_type == FIELD_VECTOR)
delete retval.m_pVector;
return pFunc->m_desc.m_ReturnType != FIELD_VOID;
return sq_retval;
}
@ -1485,12 +1511,8 @@ SQInteger constructor_stub(HSQUIRRELVM vm)
void* instance = pClassDesc->m_pfnConstruct();
if (!sq_isnull(pSquirrelVM->lastError_))
{
sq_pushobject(vm, pSquirrelVM->lastError_);
sq_resetobject(&pSquirrelVM->lastError_);
return sq_throwobject(vm);
}
// expect construction to always succeed
Assert(sq_isnull(pSquirrelVM->lastError_));
{
SQUserPointer p;
@ -1547,19 +1569,22 @@ SQInteger get_stub(HSQUIRRELVM vm)
}
ScriptVariant_t var;
SQInteger sq_retval = 0;
if (classInstanceData &&
classInstanceData->instance &&
classInstanceData->desc->pHelper &&
classInstanceData->desc->pHelper->Get(classInstanceData->instance, key, var))
{
PushVariant(vm, var);
sq_retval = 1;
}
else
{
return sqstd_throwerrorf(vm, "the index '%.50s' does not exist", key);
sq_retval = sqstd_throwerrorf(vm, "the index '%.50s' does not exist", key);
}
return 1;
var.Free();
return sq_retval;
}
SQInteger set_stub(HSQUIRRELVM vm)
@ -1576,122 +1601,22 @@ SQInteger set_stub(HSQUIRRELVM vm)
}
ScriptVariant_t var;
SQInteger sq_retval = 0;
getVariant( vm, -1, var );
if (classInstanceData &&
if (!(
classInstanceData &&
classInstanceData->instance &&
classInstanceData->desc->pHelper &&
classInstanceData->desc->pHelper->Set(classInstanceData->instance, key, var))
classInstanceData->desc->pHelper->Set(classInstanceData->instance, key, var)
))
{
sq_pop(vm, 1);
}
else
{
sq_pop(vm, 1);
return sqstd_throwerrorf(vm, "the index '%.50s' does not exist", key);
}
return 0;
}
SQInteger add_stub(HSQUIRRELVM vm)
{
ClassInstanceData* classInstanceData = nullptr;
sq_getinstanceup(vm, 1, (SQUserPointer*)&classInstanceData, 0);
ScriptVariant_t var;
getVariant( vm, 1, var );
if (classInstanceData &&
classInstanceData->instance &&
classInstanceData->desc->pHelper)
{
ScriptVariant_t *result = classInstanceData->desc->pHelper->Add( classInstanceData->instance, var );
if (result != nullptr)
{
PushVariant( vm, *result );
sq_pop(vm, 1);
return 1;
}
sq_retval = sqstd_throwerrorf(vm, "the index '%.50s' does not exist", key);
}
var.Free();
sq_pop(vm, 1);
return sqstd_throwerrorf(vm, "invalid arith op +");
}
SQInteger sub_stub(HSQUIRRELVM vm)
{
ClassInstanceData* classInstanceData = nullptr;
sq_getinstanceup(vm, 1, (SQUserPointer*)&classInstanceData, 0);
ScriptVariant_t var;
getVariant( vm, 1, var );
if (classInstanceData &&
classInstanceData->instance &&
classInstanceData->desc->pHelper)
{
ScriptVariant_t *result = classInstanceData->desc->pHelper->Subtract( classInstanceData->instance, var );
if (result != nullptr)
{
PushVariant( vm, *result );
sq_pop(vm, 1);
return 1;
}
}
sq_pop(vm, 1);
return sqstd_throwerrorf(vm, "invalid arith op -");
}
SQInteger mul_stub(HSQUIRRELVM vm)
{
ClassInstanceData* classInstanceData = nullptr;
sq_getinstanceup(vm, 1, (SQUserPointer*)&classInstanceData, 0);
ScriptVariant_t var;
getVariant( vm, 1, var );
if (classInstanceData &&
classInstanceData->instance &&
classInstanceData->desc->pHelper )
{
ScriptVariant_t *result = classInstanceData->desc->pHelper->Add( classInstanceData->instance, var );
if (result != nullptr)
{
PushVariant( vm, *result );
sq_pop(vm, 1);
return 1;
}
}
sq_pop(vm, 1);
return sqstd_throwerrorf(vm, "invalid arith op *");
}
SQInteger div_stub(HSQUIRRELVM vm)
{
ClassInstanceData* classInstanceData = nullptr;
sq_getinstanceup(vm, 1, (SQUserPointer*)&classInstanceData, 0);
ScriptVariant_t var;
getVariant( vm, 1, var );
if (classInstanceData &&
classInstanceData->instance &&
classInstanceData->desc->pHelper )
{
ScriptVariant_t *result = classInstanceData->desc->pHelper->Add( classInstanceData->instance, var );
if (result != nullptr)
{
PushVariant( vm, *result );
sq_pop(vm, 1);
return 1;
}
}
sq_pop(vm, 1);
return sqstd_throwerrorf(vm, "invalid arith op /");
return sq_retval;
}
SQInteger IsValid_stub(HSQUIRRELVM vm)
@ -2479,6 +2404,7 @@ void SquirrelVM::RegisterFunction(ScriptFunctionBinding_t* pScriptFunction)
return;
char typemask[64];
Assert(pScriptFunction->m_desc.m_Parameters.Count() < sizeof(typemask));
if (!CreateParamCheck(*pScriptFunction, typemask))
{
return;
@ -2564,22 +2490,6 @@ bool SquirrelVM::RegisterClass(ScriptClassDesc_t* pClassDesc)
sq_newclosure(vm_, set_stub, 0);
sq_newslot(vm_, -3, SQFalse);
sq_pushstring(vm_, "_add", -1);
sq_newclosure(vm_, add_stub, 0);
sq_newslot(vm_, -3, SQFalse);
sq_pushstring(vm_, "_sub", -1);
sq_newclosure(vm_, sub_stub, 0);
sq_newslot(vm_, -3, SQFalse);
sq_pushstring(vm_, "_mul", -1);
sq_newclosure(vm_, mul_stub, 0);
sq_newslot(vm_, -3, SQFalse);
sq_pushstring(vm_, "_div", -1);
sq_newclosure(vm_, div_stub, 0);
sq_newslot(vm_, -3, SQFalse);
sq_pushstring(vm_, "IsValid", -1);
sq_newclosure(vm_, IsValid_stub, 0);
sq_newslot(vm_, -3, SQFalse);
@ -2598,6 +2508,7 @@ bool SquirrelVM::RegisterClass(ScriptClassDesc_t* pClassDesc)
auto& scriptFunction = pClassDesc->m_FunctionBindings[i];
char typemask[64];
Assert(scriptFunction.m_desc.m_Parameters.Count() < sizeof(typemask));
if (!CreateParamCheck(scriptFunction, typemask))
{
Warning("Unable to create param check for %s.%s\n",
@ -3138,6 +3049,7 @@ void SquirrelVM::ReleaseValue(ScriptVariant_t& value)
// Let's prevent this being called again and giving some UB
value.m_type = FIELD_VOID;
value.m_flags = 0;
}
bool SquirrelVM::ClearValue(HSCRIPT hScope, const char* pszKey)