mirror of
https://github.com/mapbase-source/source-sdk-2013.git
synced 2025-05-19 01:58:09 +03:00
259 lines
6.9 KiB
C++
259 lines
6.9 KiB
C++
//========= Mapbase - https://github.com/mapbase-source/source-sdk-2013 ============//
|
|
//
|
|
// Purpose: Custom client-side equivalent of logic_script.
|
|
//
|
|
// $NoKeywords: $
|
|
//=============================================================================//
|
|
|
|
#include "cbase.h"
|
|
#include "vscript_shared.h"
|
|
#include "tier1/fmtstr.h"
|
|
|
|
#ifdef CLIENT_DLL
|
|
ConVar cl_script_think_interval( "cl_script_think_interval", "0.1" );
|
|
#endif
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: An entity that acts as a container for client-side game scripts.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#define MAX_SCRIPT_GROUP_CLIENT 8
|
|
|
|
class CLogicScriptClient : public CBaseEntity
|
|
{
|
|
public:
|
|
DECLARE_CLASS( CLogicScriptClient, CBaseEntity );
|
|
DECLARE_DATADESC();
|
|
DECLARE_NETWORKCLASS();
|
|
|
|
#ifdef CLIENT_DLL
|
|
void OnDataChanged( DataUpdateType_t type )
|
|
{
|
|
BaseClass::OnDataChanged( type );
|
|
|
|
if ( !m_ScriptScope.IsInitialized() )
|
|
{
|
|
RunVScripts();
|
|
}
|
|
}
|
|
#else
|
|
int UpdateTransmitState() { return SetTransmitState( FL_EDICT_ALWAYS ); }
|
|
#endif
|
|
|
|
bool KeyValue( const char *szKeyName, const char *szValue )
|
|
{
|
|
if ( FStrEq( szKeyName, "vscripts" ) )
|
|
{
|
|
Q_strcpy( m_iszClientScripts.GetForModify(), szValue );
|
|
}
|
|
|
|
return BaseClass::KeyValue( szKeyName, szValue );
|
|
}
|
|
|
|
void RunVScripts()
|
|
{
|
|
#ifdef CLIENT_DLL
|
|
if (m_iszClientScripts == NULL_STRING)
|
|
{
|
|
CGMsg( 0, CON_GROUP_VSCRIPT, "%s has no client scripts", GetDebugName() );
|
|
return;
|
|
}
|
|
|
|
if (g_pScriptVM == NULL)
|
|
{
|
|
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, m_iszClientScripts.Get() );
|
|
CUtlStringList szScripts;
|
|
|
|
V_SplitString( szScriptsList, " ", szScripts );
|
|
|
|
for (int i = 0; i < szScripts.Count(); i++)
|
|
{
|
|
CGMsg( 0, CON_GROUP_VSCRIPT, "%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_bClientThink)
|
|
{
|
|
SetNextClientThink( CLIENT_THINK_ALWAYS );
|
|
}
|
|
#else
|
|
// Avoids issues from having m_iszVScripts set without actually having a script scope
|
|
ValidateScriptScope();
|
|
|
|
if (m_bRunOnServer)
|
|
{
|
|
BaseClass::RunVScripts();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#ifdef CLIENT_DLL
|
|
void ClientThink()
|
|
{
|
|
ScriptVariant_t varThinkRetVal;
|
|
if (CallScriptFunction("ClientThink", &varThinkRetVal))
|
|
{
|
|
float flThinkFrequency = 0.0f;
|
|
if (!varThinkRetVal.AssignTo(&flThinkFrequency))
|
|
{
|
|
// use default think interval if script think function doesn't provide one
|
|
flThinkFrequency = cl_script_think_interval.GetFloat();
|
|
}
|
|
|
|
if (flThinkFrequency == CLIENT_THINK_ALWAYS)
|
|
SetNextClientThink( CLIENT_THINK_ALWAYS );
|
|
else
|
|
SetNextClientThink( gpGlobals->curtime + flThinkFrequency );
|
|
}
|
|
else
|
|
{
|
|
DevWarning("%s FAILED to call client script think function!\n", GetDebugName());
|
|
}
|
|
|
|
BaseClass::ClientThink();
|
|
}
|
|
|
|
void OnSave()
|
|
{
|
|
// HACKHACK: Save the next think in the VM since the VM is saved
|
|
if (m_bClientThink)
|
|
{
|
|
g_pScriptVM->SetValue( m_ScriptScope, "__c_think", GetNextThink() );
|
|
}
|
|
|
|
BaseClass::OnSave();
|
|
}
|
|
|
|
void OnRestore()
|
|
{
|
|
// HACKHACK: See OnSave()
|
|
if (m_bClientThink)
|
|
{
|
|
ScriptVariant_t flNextThink;
|
|
if (g_pScriptVM->GetValue( m_ScriptScope, "__c_think", &flNextThink ))
|
|
{
|
|
SetNextClientThink( flNextThink );
|
|
}
|
|
}
|
|
|
|
BaseClass::OnRestore();
|
|
}
|
|
#else
|
|
void InputCallScriptFunctionClient( inputdata_t &inputdata )
|
|
{
|
|
// TODO: Support for specific players?
|
|
CBroadcastRecipientFilter filter;
|
|
filter.MakeReliable();
|
|
|
|
const char *pszFunction = inputdata.value.String();
|
|
if (strlen( pszFunction ) > 64)
|
|
{
|
|
Msg("%s CallScriptFunctionClient: \"%s\" is too long at %i characters, must be 64 or less\n", GetDebugName(), pszFunction, strlen(pszFunction));
|
|
return;
|
|
}
|
|
|
|
UserMessageBegin( filter, "CallClientScriptFunction" );
|
|
WRITE_STRING( pszFunction ); // function
|
|
WRITE_SHORT( entindex() ); // entity
|
|
MessageEnd();
|
|
}
|
|
#endif
|
|
|
|
//CNetworkArray( string_t, m_iszGroupMembers, MAX_SCRIPT_GROUP_CLIENT );
|
|
CNetworkString( m_iszClientScripts, 128 );
|
|
CNetworkVar( bool, m_bClientThink );
|
|
|
|
#ifndef CLIENT_DLL
|
|
bool m_bRunOnServer;
|
|
#endif
|
|
};
|
|
|
|
LINK_ENTITY_TO_CLASS( logic_script_client, CLogicScriptClient );
|
|
|
|
BEGIN_DATADESC( CLogicScriptClient )
|
|
|
|
// TODO: Does this need to be saved?
|
|
//DEFINE_AUTO_ARRAY( m_iszClientScripts, FIELD_CHARACTER ),
|
|
|
|
//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_bClientThink, FIELD_BOOLEAN, "ClientThink" ),
|
|
|
|
#ifndef CLIENT_DLL
|
|
DEFINE_KEYFIELD( m_bRunOnServer, FIELD_BOOLEAN, "RunOnServer" ),
|
|
|
|
DEFINE_INPUTFUNC( FIELD_STRING, "CallScriptFunctionClient", InputCallScriptFunctionClient ),
|
|
#endif
|
|
|
|
END_DATADESC()
|
|
|
|
IMPLEMENT_NETWORKCLASS_DT( CLogicScriptClient, DT_LogicScriptClient )
|
|
|
|
#ifdef CLIENT_DLL
|
|
//RecvPropArray( RecvPropString( RECVINFO( m_iszGroupMembers[0] ) ), m_iszGroupMembers ),
|
|
RecvPropString( RECVINFO( m_iszClientScripts ) ),
|
|
RecvPropBool( RECVINFO( m_bClientThink ) ),
|
|
#else
|
|
//SendPropArray( SendPropStringT( SENDINFO_ARRAY( m_iszGroupMembers ) ), m_iszGroupMembers ),
|
|
SendPropString( SENDINFO( m_iszClientScripts ) ),
|
|
SendPropBool( SENDINFO( m_bClientThink ) ),
|
|
#endif
|
|
|
|
END_NETWORK_TABLE()
|