Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prevent return of dangling Vector/QAngle to VScript #321

Open
wants to merge 6 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions sp/src/game/server/hl2/proto_sniper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 )
Expand Down
3 changes: 2 additions & 1 deletion sp/src/game/shared/mapbase/vscript_consts_shared.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,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
Expand Down
144 changes: 73 additions & 71 deletions sp/src/public/vscript/ivscript.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -389,88 +390,59 @@ 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 ); }

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; }
#endif
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 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()
{
T value;
AssignTo( &value );
return value;
}
void operator=( Vector &&vec ) = delete;
void operator=( QAngle &&ang ) = delete;
#endif

template <typename T>
bool AssignTo( T *pDest )
void Free()
{
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 )
Expand Down Expand Up @@ -525,25 +497,38 @@ struct ScriptVariant_t

bool AssignTo( ScriptVariant_t *pDest )
{
pDest->Free();
pDest->m_type = m_type;
if ( m_type == FIELD_VECTOR )
{
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 )
if ( m_flags & SV_FREE )
{
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;
Expand All @@ -565,8 +550,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
Expand Down Expand Up @@ -659,7 +661,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)

//-----------------------------------------------------------------------------
//
Expand Down
Loading
Loading