Added VScript material proxy, exposed more stuff to clientside VScript

This commit is contained in:
Blixibon 2020-05-30 10:48:00 -05:00
parent 0f80bfad11
commit 4966b79f84
5 changed files with 381 additions and 2 deletions

View File

@ -431,6 +431,35 @@ BEGIN_ENT_SCRIPTDESC_ROOT( C_BaseEntity, "Root class of all client-side entities
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" )
#ifdef MAPBASE_VSCRIPT
DEFINE_SCRIPTFUNC( GetHealth, "" )
DEFINE_SCRIPTFUNC( GetMaxHealth, "" )
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( GetEntityName, "GetName", "" )
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( ScriptGetAngles, "GetAngles", "Get entity pitch, yaw, roll as a vector" )
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( 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( GetEffects, "Get effects" )
DEFINE_SCRIPTFUNC( IsEffectActive, "Check if an effect is active" )
#endif
END_SCRIPTDESC();
#ifndef NO_ENTITY_PREDICTION
@ -6482,6 +6511,35 @@ HSCRIPT C_BaseEntity::GetScriptInstance()
return m_hScriptInstance;
}
#ifdef MAPBASE_VSCRIPT
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT C_BaseEntity::ScriptGetMoveParent( void )
{
return ToHScript( GetMoveParent() );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT C_BaseEntity::ScriptGetRootMoveParent()
{
return ToHScript( GetRootMoveParent() );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT C_BaseEntity::ScriptFirstMoveChild( void )
{
return ToHScript( FirstMoveChild() );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT C_BaseEntity::ScriptNextMovePeer( void )
{
return ToHScript( NextMovePeer() );
}
#endif
//------------------------------------------------------------------------------
void CC_CL_Find_Ent( const CCommand& args )
{

View File

@ -1133,6 +1133,26 @@ public:
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; }
#ifdef MAPBASE_VSCRIPT
const char* ScriptGetModelName( void ) const { return STRING(GetModelName()); }
void ScriptEmitSound(const char* soundname);
float ScriptSoundDuration(const char* soundname, const char* actormodel);
void VScriptPrecacheScriptSound(const char* soundname);
const Vector& ScriptEyePosition(void) { static Vector vec; vec = EyePosition(); return vec; }
const Vector& ScriptGetAngles(void) { static Vector vec; QAngle qa = GetAbsAngles(); vec.x = qa.x; vec.y = qa.y; vec.z = qa.z; return vec; }
const Vector& ScriptGetBoundingMins( void ) { return m_Collision.OBBMins(); }
const Vector& ScriptGetBoundingMaxs( void ) { return m_Collision.OBBMaxs(); }
HSCRIPT ScriptGetMoveParent( void );
HSCRIPT ScriptGetRootMoveParent();
HSCRIPT ScriptFirstMoveChild( void );
HSCRIPT ScriptNextMovePeer( void );
#endif
// Stubs on client
void NetworkStateManualMode( bool activate ) { }
void NetworkStateChanged() { }

View File

@ -480,6 +480,13 @@ C_BasePlayer::~C_BasePlayer()
s_pLocalPlayer = NULL;
}
#ifdef MAPBASE_VSCRIPT
if ( IsLocalPlayer() && g_pScriptVM )
{
g_pScriptVM->SetValue( "player", SCRIPT_VARIANT_NULL );
}
#endif
delete m_pFlashlight;
}
@ -974,6 +981,16 @@ void C_BasePlayer::OnRestore()
input->ClearInputButton( IN_ATTACK | IN_ATTACK2 );
// GetButtonBits() has to be called for the above to take effect
input->GetButtonBits( 0 );
#ifdef MAPBASE_VSCRIPT
// 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_pScriptVM )
{
g_pScriptVM->SetValue( "player", GetScriptInstance() );
}
#endif
}
// For ammo history icons to current value so they don't flash on level transtions

View File

@ -18,6 +18,9 @@
#endif
#ifdef MAPBASE_VSCRIPT
#include "c_world.h"
#include "proxyentity.h"
#include "materialsystem/imaterial.h"
#include "materialsystem/imaterialvar.h"
#endif
extern IScriptManager *scriptmanager;
@ -37,6 +40,280 @@ extern ScriptClassDesc_t * GetScriptDesc( CBaseEntity * );
#endif // VMPROFILE
#ifdef MAPBASE_VSCRIPT
#define SCRIPT_MAT_PROXY_MAX_VARS 8
//-----------------------------------------------------------------------------
// Purpose: A material proxy which runs a VScript and allows it to read/write
// to material variables.
//-----------------------------------------------------------------------------
class CScriptMaterialProxy : public IMaterialProxy
{
public:
CScriptMaterialProxy();
virtual ~CScriptMaterialProxy();
virtual void Release( void );
virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
virtual void OnBind( void *pRenderable );
virtual IMaterial *GetMaterial() { return NULL; }
// It would be more preferable to init the script stuff in Init(), but
// the VM isn't usually active by that time, so we have to init it when
// it's first called in OnBind().
bool InitScript();
bool ValidateIndex(int i)
{
if (i > SCRIPT_MAT_PROXY_MAX_VARS || i < 0)
{
Warning("VScriptProxy: %i out of range", i);
return false;
}
return true;
}
const char *GetVarString( int i );
int GetVarInt( int i );
float GetVarFloat( int i );
const Vector& GetVarVector( int i );
void SetVarString( int i, const char *value );
void SetVarInt( int i, int value );
void SetVarFloat( int i, float value );
void SetVarVector( int i, const Vector &value );
private:
IMaterialVar *m_MaterialVars[SCRIPT_MAT_PROXY_MAX_VARS];
// Save the keyvalue string for InitScript()
char m_szFilePath[MAX_PATH];
CScriptScope m_ScriptScope;
HSCRIPT m_hScriptInstance;
HSCRIPT m_hFuncOnBind;
};
BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptMaterialProxy, "CScriptMaterialProxy", "Material proxy for VScript" )
DEFINE_SCRIPTFUNC( GetVarString, "Gets a material var's string value" )
DEFINE_SCRIPTFUNC( GetVarInt, "Gets a material var's int value" )
DEFINE_SCRIPTFUNC( GetVarFloat, "Gets a material var's float value" )
DEFINE_SCRIPTFUNC( GetVarVector, "Gets a material var's vector value" )
DEFINE_SCRIPTFUNC( SetVarString, "Sets a material var's string value" )
DEFINE_SCRIPTFUNC( SetVarInt, "Sets a material var's int value" )
DEFINE_SCRIPTFUNC( SetVarFloat, "Sets a material var's float value" )
DEFINE_SCRIPTFUNC( SetVarVector, "Sets a material var's vector value" )
END_SCRIPTDESC();
CScriptMaterialProxy::CScriptMaterialProxy()
{
m_hScriptInstance = NULL;
m_hFuncOnBind = NULL;
}
CScriptMaterialProxy::~CScriptMaterialProxy()
{
}
//-----------------------------------------------------------------------------
// Cleanup
//-----------------------------------------------------------------------------
void CScriptMaterialProxy::Release( void )
{
if ( m_hScriptInstance && g_pScriptVM )
{
g_pScriptVM->RemoveInstance( m_hScriptInstance );
m_hScriptInstance = NULL;
}
delete this;
}
bool CScriptMaterialProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
{
for (KeyValues *pKey = pKeyValues->GetFirstSubKey(); pKey != NULL; pKey = pKey->GetNextKey())
{
// Get each variable we're looking for
if (Q_strnicmp( pKey->GetName(), "var", 3 ) == 0)
{
int index = atoi(pKey->GetName() + 3);
if (index > SCRIPT_MAT_PROXY_MAX_VARS)
{
Warning("VScript material proxy only supports 8 vars (not %i)\n", index);
continue;
}
bool foundVar;
m_MaterialVars[index] = pMaterial->FindVar( pKey->GetString(), &foundVar );
// Don't init if we didn't find the var
if (!foundVar)
return false;
}
else if (FStrEq( pKey->GetName(), "scriptfile" ))
{
Q_strncpy( m_szFilePath, pKey->GetString(), sizeof( m_szFilePath ) );
}
}
return true;
}
bool CScriptMaterialProxy::InitScript()
{
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;
}
char* iszScriptId = (char*)stackalloc( 1024 );
g_pScriptVM->GenerateUniqueKey("VScriptProxy", iszScriptId, 1024);
m_hScriptInstance = g_pScriptVM->RegisterInstance( GetScriptDescForClass( CScriptMaterialProxy ), this );
g_pScriptVM->SetInstanceUniqeId( m_hScriptInstance, iszScriptId );
bool bResult = m_ScriptScope.Init( iszScriptId );
if (!bResult)
{
DevMsg("VScriptProxy couldn't create ScriptScope!\n");
return false;
}
g_pScriptVM->SetValue( m_ScriptScope, "self", m_hScriptInstance );
}
// Don't init if we can't run the script
if (!VScriptRunScript( m_szFilePath, m_ScriptScope, true ))
return false;
m_hFuncOnBind = m_ScriptScope.LookupFunction( "OnBind" );
if (!m_hFuncOnBind)
{
// Don't init if we can't find our func
Warning("VScript material proxy can't find OnBind function\n");
return false;
}
return true;
}
void CScriptMaterialProxy::OnBind( void *pRenderable )
{
if( !pRenderable )
return;
if (m_hFuncOnBind != NULL)
{
IClientRenderable *pRend = ( IClientRenderable* )pRenderable;
C_BaseEntity *pEnt = pRend->GetIClientUnknown()->GetBaseEntity();
if ( pEnt )
{
g_pScriptVM->SetValue( m_ScriptScope, "entity", pEnt->GetScriptInstance() );
}
else
{
// Needs to register as a null value so the script doesn't break if it looks for an entity
g_pScriptVM->SetValue( m_ScriptScope, "entity", SCRIPT_VARIANT_NULL );
}
m_ScriptScope.Call( m_hFuncOnBind, NULL );
g_pScriptVM->ClearValue( m_ScriptScope, "entity" );
}
else
{
// The VM might not exist if we do it from Init(), so we have to do it here.
// TODO: We have no handling for if this fails, how do you cancel a proxy?
if (InitScript())
OnBind( pRenderable );
}
}
const char *CScriptMaterialProxy::GetVarString( int i )
{
if (!ValidateIndex( i ) || !m_MaterialVars[i])
return NULL;
return m_MaterialVars[i]->GetStringValue();
}
int CScriptMaterialProxy::GetVarInt( int i )
{
if (!ValidateIndex( i ) || !m_MaterialVars[i])
return 0;
return m_MaterialVars[i]->GetIntValue();
}
float CScriptMaterialProxy::GetVarFloat( int i )
{
if (!ValidateIndex( i ) || !m_MaterialVars[i])
return 0.0f;
return m_MaterialVars[i]->GetFloatValue();
}
const Vector& CScriptMaterialProxy::GetVarVector( int i )
{
if (!ValidateIndex( i ) || !m_MaterialVars[i])
return vec3_origin;
if (m_MaterialVars[i]->GetType() != MATERIAL_VAR_TYPE_VECTOR)
return vec3_origin;
// This is really bad. Too bad!
return *(reinterpret_cast<const Vector*>(m_MaterialVars[i]->GetVecValue()));
}
void CScriptMaterialProxy::SetVarString( int i, const char *value )
{
if (!ValidateIndex( i ) || !m_MaterialVars[i])
return;
return m_MaterialVars[i]->SetStringValue( value );
}
void CScriptMaterialProxy::SetVarInt( int i, int value )
{
if (!ValidateIndex( i ) || !m_MaterialVars[i])
return;
return m_MaterialVars[i]->SetIntValue( value );
}
void CScriptMaterialProxy::SetVarFloat( int i, float value )
{
if (!ValidateIndex( i ) || !m_MaterialVars[i])
return;
return m_MaterialVars[i]->SetFloatValue( value );
}
void CScriptMaterialProxy::SetVarVector( int i, const Vector &value )
{
if (!ValidateIndex( i ) || !m_MaterialVars[i])
return;
return m_MaterialVars[i]->SetVecValue( value.Base(), 3 );
}
EXPOSE_INTERFACE( CScriptMaterialProxy, IMaterialProxy, "VScriptProxy" IMATERIAL_PROXY_INTERFACE_VERSION );
#endif
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
@ -181,6 +458,13 @@ public:
virtual void LevelInitPostEntity( void )
{
m_bAllowEntityCreationInScripts = false;
#ifdef MAPBASE_VSCRIPT
C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
if (pPlayer)
{
g_pScriptVM->SetValue( "player", pPlayer->GetScriptInstance() );
}
#endif
}
virtual void LevelShutdownPostEntity( void )

View File

@ -1217,7 +1217,7 @@ void CBaseEntity::EmitSound( const char *soundname, HSOUNDSCRIPTHANDLE& handle,
EmitSound( filter, entindex(), params, handle );
}
#if !defined ( CLIENT_DLL )
#if !defined ( CLIENT_DLL ) || defined( MAPBASE_VSCRIPT )
void CBaseEntity::ScriptEmitSound( const char *soundname )
{
EmitSound( soundname );
@ -1499,7 +1499,7 @@ HSOUNDSCRIPTHANDLE CBaseEntity::PrecacheScriptSound( const char *soundname )
#endif
}
#if !defined ( CLIENT_DLL )
#if !defined ( CLIENT_DLL ) || defined( MAPBASE_VSCRIPT )
// Same as server version of above, but signiture changed so it can be deduced by the macros
void CBaseEntity::VScriptPrecacheScriptSound(const char* soundname)
{