From 6ed8b31091c12b95bcbf3b720f0966190bfb02f5 Mon Sep 17 00:00:00 2001 From: samisalreadytaken <46823719+samisalreadytaken@users.noreply.github.com> Date: Fri, 19 Mar 2021 16:44:12 +0200 Subject: [PATCH 1/2] vscript additions: - Added CBaseEntity::Activate - Added CBaseEntity::SetSolid - Added CBaseEntity::GetSolid - Added C_BaseEntity::UpdateOnRemove - Added hook behaviour on CScriptConCommand - Added more script overridable concommands - Added CScriptConvarAccessor::SetChangeCallback - Added CScriptGlowObjectManager - Added CScriptSteamAPI --- sp/src/game/client/c_baseentity.cpp | 15 +- sp/src/game/client/glow_outline_effect.h | 4 + sp/src/game/server/baseentity.cpp | 7 +- .../shared/mapbase/vscript_singletons.cpp | 298 +++++++++++++++--- sp/src/tier1/convar.cpp | 3 + 5 files changed, 286 insertions(+), 41 deletions(-) diff --git a/sp/src/game/client/c_baseentity.cpp b/sp/src/game/client/c_baseentity.cpp index a3b4037812..a7bb37a4f0 100644 --- a/sp/src/game/client/c_baseentity.cpp +++ b/sp/src/game/client/c_baseentity.cpp @@ -428,6 +428,10 @@ BEGIN_RECV_TABLE_NOBASE( C_BaseEntity, DT_AnimTimeMustBeFirst ) RecvPropInt( RECVINFO(m_flAnimTime), 0, RecvProxy_AnimTime ), END_RECV_TABLE() +#ifdef MAPBASE_VSCRIPT +ScriptHook_t CBaseEntity::g_Hook_UpdateOnRemove; +#endif + BEGIN_ENT_SCRIPTDESC_ROOT( C_BaseEntity, "Root class of all client-side entities" ) DEFINE_SCRIPT_INSTANCE_HELPER( &g_BaseEntityScriptInstanceHelper ) DEFINE_SCRIPTFUNC_NAMED( GetAbsOrigin, "GetOrigin", "" ) @@ -550,7 +554,10 @@ BEGIN_ENT_SCRIPTDESC_ROOT( C_BaseEntity, "Root class of all client-side entities DEFINE_SCRIPTFUNC_NAMED( ScriptSetContextThink, "SetContextThink", "Set a think function on this entity." ) -#endif + + DEFINE_SIMPLE_SCRIPTHOOK( CBaseEntity::g_Hook_UpdateOnRemove, "UpdateOnRemove", FIELD_VOID, "Called when the entity is being removed." ) + +#endif // MAPBASE_VSCRIPT END_SCRIPTDESC(); @@ -1340,6 +1347,12 @@ void C_BaseEntity::Term() if ( m_hScriptInstance ) { +#ifdef MAPBASE_VSCRIPT + if ( m_ScriptScope.IsInitialized() ) + { + g_Hook_UpdateOnRemove.Call( m_ScriptScope, NULL, NULL ); + } +#endif g_pScriptVM->RemoveInstance( m_hScriptInstance ); m_hScriptInstance = NULL; diff --git a/sp/src/game/client/glow_outline_effect.h b/sp/src/game/client/glow_outline_effect.h index aac399d734..111328620d 100644 --- a/sp/src/game/client/glow_outline_effect.h +++ b/sp/src/game/client/glow_outline_effect.h @@ -150,6 +150,10 @@ class CGlowObjectManager static const int ENTRY_IN_USE = -2; }; +#ifdef MAPBASE_VSCRIPT + // For unregistration boundary check +public: +#endif CUtlVector< GlowObjectDefinition_t > m_GlowObjectDefinitions; int m_nFirstFreeSlot; }; diff --git a/sp/src/game/server/baseentity.cpp b/sp/src/game/server/baseentity.cpp index 1b71f9fd3b..63c964394d 100644 --- a/sp/src/game/server/baseentity.cpp +++ b/sp/src/game/server/baseentity.cpp @@ -2311,6 +2311,8 @@ BEGIN_ENT_SCRIPTDESC_ROOT( CBaseEntity, "Root class of all server-side entities" DEFINE_SCRIPTFUNC_NAMED( ScriptGetModelKeyValues, "GetModelKeyValues", "Get a KeyValue class instance on this entity's model") #ifdef MAPBASE_VSCRIPT + DEFINE_SCRIPTFUNC( Activate, "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptIsVisible, "IsVisible", "Check if the specified position can be visible to this entity." ) DEFINE_SCRIPTFUNC_NAMED( ScriptIsEntVisible, "IsEntVisible", "Check if the specified entity can be visible to this entity." ) DEFINE_SCRIPTFUNC_NAMED( ScriptIsVisibleWithMask, "IsVisibleWithMask", "Check if the specified position can be visible to this entity with a specific trace mask." ) @@ -2408,7 +2410,10 @@ BEGIN_ENT_SCRIPTDESC_ROOT( CBaseEntity, "Root class of all server-side entities" DEFINE_SCRIPTFUNC( SetFriction, "" ) DEFINE_SCRIPTFUNC( GetMass, "" ) DEFINE_SCRIPTFUNC( SetMass, "" ) - + + DEFINE_SCRIPTFUNC_NAMED( ScriptGetSolid, "GetSolid", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptSetSolid, "SetSolid", "" ) + DEFINE_SCRIPTFUNC( GetSolidFlags, "Get solid flags" ) DEFINE_SCRIPTFUNC( AddSolidFlags, "Add solid flags" ) DEFINE_SCRIPTFUNC( RemoveSolidFlags, "Remove solid flags" ) diff --git a/sp/src/game/shared/mapbase/vscript_singletons.cpp b/sp/src/game/shared/mapbase/vscript_singletons.cpp index c5e514996d..412723b1a8 100644 --- a/sp/src/game/shared/mapbase/vscript_singletons.cpp +++ b/sp/src/game/shared/mapbase/vscript_singletons.cpp @@ -30,6 +30,10 @@ #include "c_te_legacytempents.h" #include "iefx.h" #include "dlight.h" + +#if !defined(NO_STEAM) +#include "steam/steam_api.h" +#endif #endif #include "vscript_singletons.h" @@ -2170,12 +2174,13 @@ class CScriptConCommand : public ICommandCallback, public ICommandCompletionCall ~CScriptConCommand() { Unregister(); - delete m_cmd; + delete m_pBase; } - CScriptConCommand( const char *name, HSCRIPT fn, const char *helpString, int flags ) + CScriptConCommand( const char *name, HSCRIPT fn, const char *helpString, int flags, ConCommand *pLinked = NULL ) { - m_cmd = new ConCommand( name, this, helpString, flags, 0 ); + m_pBase = new ConCommand( name, this, helpString, flags, 0 ); + m_pLinked = pLinked; m_hCallback = fn; m_hCompletionCallback = NULL; m_nCmdNameLen = V_strlen(name) + 1; @@ -2191,10 +2196,15 @@ class CScriptConCommand : public ICommandCallback, public ICommandCompletionCall { vArgv[i] = command[i]; } - if ( g_pScriptVM->ExecuteFunction( m_hCallback, vArgv, count, NULL, NULL, true ) == SCRIPT_ERROR ) + ScriptVariant_t ret; + if ( g_pScriptVM->ExecuteFunction( m_hCallback, vArgv, count, &ret, NULL, true ) == SCRIPT_ERROR ) { DevWarning( 1, "CScriptConCommand: invalid callback for '%s'\n", command[0] ); } + if ( m_pLinked && (ret.m_type == FIELD_BOOLEAN) && ret.m_bool ) + { + m_pLinked->Dispatch( command ); + } } int CommandCompletionCallback( const char *partial, CUtlVector< CUtlString > &commands ) @@ -2249,17 +2259,17 @@ class CScriptConCommand : public ICommandCallback, public ICommandCompletionCall if (fn) { - if ( !m_cmd->IsRegistered() ) + if ( !m_pBase->IsRegistered() ) return; - m_cmd->m_pCommandCompletionCallback = this; - m_cmd->m_bHasCompletionCallback = true; + m_pBase->m_pCommandCompletionCallback = this; + m_pBase->m_bHasCompletionCallback = true; m_hCompletionCallback = fn; } else { - m_cmd->m_pCommandCompletionCallback = NULL; - m_cmd->m_bHasCompletionCallback = false; + m_pBase->m_pCommandCompletionCallback = NULL; + m_pBase->m_bHasCompletionCallback = false; m_hCompletionCallback = NULL; } } @@ -2268,7 +2278,7 @@ class CScriptConCommand : public ICommandCallback, public ICommandCompletionCall { if (fn) { - if ( !m_cmd->IsRegistered() ) + if ( !m_pBase->IsRegistered() ) Register(); if ( m_hCallback ) @@ -2283,8 +2293,8 @@ class CScriptConCommand : public ICommandCallback, public ICommandCompletionCall inline void Unregister() { - if ( g_pCVar && m_cmd->IsRegistered() ) - g_pCVar->UnregisterConCommand( m_cmd ); + if ( g_pCVar && m_pBase->IsRegistered() ) + g_pCVar->UnregisterConCommand( m_pBase ); if ( g_pScriptVM ) { @@ -2301,13 +2311,14 @@ class CScriptConCommand : public ICommandCallback, public ICommandCompletionCall inline void Register() { if ( g_pCVar ) - g_pCVar->RegisterConCommand( m_cmd ); + g_pCVar->RegisterConCommand( m_pBase ); } HSCRIPT m_hCallback; HSCRIPT m_hCompletionCallback; int m_nCmdNameLen; - ConCommand *m_cmd; + ConCommand *m_pLinked; + ConCommand *m_pBase; }; class CScriptConVar @@ -2316,30 +2327,58 @@ class CScriptConVar ~CScriptConVar() { Unregister(); - delete m_cvar; + delete m_pBase; } CScriptConVar( const char *pName, const char *pDefaultValue, const char *pHelpString, int flags/*, float fMin, float fMax*/ ) { - m_cvar = new ConVar( pName, pDefaultValue, flags, pHelpString ); + m_pBase = new ConVar( pName, pDefaultValue, flags, pHelpString ); + m_hCallback = NULL; + } + + void SetChangeCallback( HSCRIPT fn ) + { + void ScriptConVarCallback( IConVar*, const char*, float ); + + if ( m_hCallback ) + g_pScriptVM->ReleaseScript( m_hCallback ); + + if (fn) + { + m_hCallback = fn; + m_pBase->InstallChangeCallback( (FnChangeCallback_t)ScriptConVarCallback ); + } + else + { + m_hCallback = NULL; + m_pBase->InstallChangeCallback( NULL ); + } } inline void Unregister() { - if ( g_pCVar && m_cvar->IsRegistered() ) - g_pCVar->UnregisterConCommand( m_cvar ); + if ( g_pCVar && m_pBase->IsRegistered() ) + g_pCVar->UnregisterConCommand( m_pBase ); + + if ( g_pScriptVM ) + { + SetChangeCallback( NULL ); + } } - ConVar *m_cvar; + HSCRIPT m_hCallback; + ConVar *m_pBase; }; +static CUtlMap< unsigned int, bool > g_ConVarsBlocked( DefLessFunc(unsigned int) ); +static CUtlMap< unsigned int, bool > g_ConCommandsOverridable( DefLessFunc(unsigned int) ); +static CUtlMap< unsigned int, CScriptConCommand* > g_ScriptConCommands( DefLessFunc(unsigned int) ); +static CUtlMap< unsigned int, CScriptConVar* > g_ScriptConVars( DefLessFunc(unsigned int) ); + + class CScriptConvarAccessor : public CAutoGameSystem { public: - static CUtlMap< unsigned int, bool > g_ConVarsBlocked; - static CUtlMap< unsigned int, bool > g_ConCommandsOverridable; - static CUtlMap< unsigned int, CScriptConCommand* > g_ScriptConCommands; - static CUtlMap< unsigned int, CScriptConVar* > g_ScriptConVars; static inline unsigned int Hash( const char*sz ){ return HashStringCaseless(sz); } public: @@ -2353,7 +2392,7 @@ class CScriptConvarAccessor : public CAutoGameSystem int idx = g_ConCommandsOverridable.Find( hash ); if ( idx == g_ConCommandsOverridable.InvalidIndex() ) return false; - return g_ConCommandsOverridable[idx]; + return true; } inline void AddBlockedConVar( const char *name ) @@ -2366,7 +2405,7 @@ class CScriptConvarAccessor : public CAutoGameSystem int idx = g_ConVarsBlocked.Find( Hash(name) ); if ( idx == g_ConVarsBlocked.InvalidIndex() ) return false; - return g_ConVarsBlocked[idx]; + return true; } public: @@ -2374,6 +2413,7 @@ class CScriptConvarAccessor : public CAutoGameSystem void SetCompletionCallback( const char *name, HSCRIPT fn ); void UnregisterCommand( const char *name ); void RegisterConvar( const char *name, const char *pDefaultValue, const char *helpString, int flags ); + void SetChangeCallback( const char *name, HSCRIPT fn ); HSCRIPT GetCommandClient() { @@ -2482,18 +2522,14 @@ class CScriptConvarAccessor : public CAutoGameSystem } g_ScriptConvarAccessor; -CUtlMap< unsigned int, bool > CScriptConvarAccessor::g_ConVarsBlocked( DefLessFunc(unsigned int) ); -CUtlMap< unsigned int, bool > CScriptConvarAccessor::g_ConCommandsOverridable( DefLessFunc(unsigned int) ); -CUtlMap< unsigned int, CScriptConCommand* > CScriptConvarAccessor::g_ScriptConCommands( DefLessFunc(unsigned int) ); -CUtlMap< unsigned int, CScriptConVar* > CScriptConvarAccessor::g_ScriptConVars( DefLessFunc(unsigned int) ); - void CScriptConvarAccessor::RegisterCommand( const char *name, HSCRIPT fn, const char *helpString, int flags ) { unsigned int hash = Hash(name); int idx = g_ScriptConCommands.Find(hash); if ( idx == g_ScriptConCommands.InvalidIndex() ) { - if ( g_pCVar->FindVar(name) || ( g_pCVar->FindCommand(name) && !IsOverridable(hash) ) ) + ConCommand *pLinked = NULL; + if ( g_pCVar->FindVar(name) || ( ((pLinked = g_pCVar->FindCommand(name)) != NULL) && !IsOverridable(hash) ) ) { DevWarning( 1, "CScriptConvarAccessor::RegisterCommand unable to register blocked ConCommand: %s\n", name ); return; @@ -2502,14 +2538,13 @@ void CScriptConvarAccessor::RegisterCommand( const char *name, HSCRIPT fn, const if ( !fn ) return; - CScriptConCommand *p = new CScriptConCommand( name, fn, helpString, flags ); + CScriptConCommand *p = new CScriptConCommand( name, fn, helpString, flags, pLinked ); g_ScriptConCommands.Insert( hash, p ); } else { CScriptConCommand *pCmd = g_ScriptConCommands[idx]; pCmd->SetCallback( fn ); - pCmd->m_cmd->AddFlags( flags ); //CGMsg( 1, CON_GROUP_VSCRIPT, "CScriptConvarAccessor::RegisterCommand replacing command already registered: %s\n", name ); } } @@ -2552,11 +2587,39 @@ void CScriptConvarAccessor::RegisterConvar( const char *name, const char *pDefau } else { - g_ScriptConVars[idx]->m_cvar->AddFlags( flags ); //CGMsg( 1, CON_GROUP_VSCRIPT, "CScriptConvarAccessor::RegisterConvar convar %s already registered\n", name ); } } +void CScriptConvarAccessor::SetChangeCallback( const char *name, HSCRIPT fn ) +{ + unsigned int hash = Hash(name); + int idx = g_ScriptConVars.Find(hash); + if ( idx != g_ScriptConVars.InvalidIndex() ) + { + g_ScriptConVars[idx]->SetChangeCallback( fn ); + } +} + +void ScriptConVarCallback( IConVar *var, const char* pszOldValue, float flOldValue ) +{ + ConVar *cvar = (ConVar*)var; + const char *name = cvar->GetName(); + unsigned int hash = CScriptConvarAccessor::Hash( name ); + int idx = g_ScriptConVars.Find(hash); + if ( idx != g_ScriptConVars.InvalidIndex() ) + { + Assert( g_ScriptConVars[idx]->m_hCallback ); + + ScriptVariant_t args[5] = { name, pszOldValue, flOldValue, cvar->GetString(), cvar->GetFloat() }; + if ( g_pScriptVM->ExecuteFunction( g_ScriptConVars[idx]->m_hCallback, args, 5, NULL, NULL, true ) == SCRIPT_ERROR ) + { + DevWarning( 1, "CScriptConVar: invalid change callback for '%s'\n", name ); + } + } +} + + bool CScriptConvarAccessor::Init() { static bool bExecOnce = false; @@ -2584,6 +2647,7 @@ bool CScriptConvarAccessor::Init() AddOverridable( "+grenade1" ); AddOverridable( "+grenade2" ); AddOverridable( "+showscores" ); + AddOverridable( "+voicerecord" ); AddOverridable( "-attack" ); AddOverridable( "-attack2" ); @@ -2605,8 +2669,11 @@ bool CScriptConvarAccessor::Init() AddOverridable( "-grenade1" ); AddOverridable( "-grenade2" ); AddOverridable( "-showscores" ); + AddOverridable( "-voicerecord" ); AddOverridable( "toggle_duck" ); + AddOverridable( "impulse" ); + AddOverridable( "use" ); AddOverridable( "lastinv" ); AddOverridable( "invnext" ); AddOverridable( "invprev" ); @@ -2618,10 +2685,16 @@ bool CScriptConvarAccessor::Init() AddOverridable( "slot5" ); AddOverridable( "slot6" ); AddOverridable( "slot7" ); + AddOverridable( "slot8" ); + AddOverridable( "slot9" ); + AddOverridable( "slot10" ); AddOverridable( "save" ); AddOverridable( "load" ); + AddOverridable( "say" ); + AddOverridable( "say_team" ); + AddBlockedConVar( "con_enable" ); AddBlockedConVar( "cl_allowdownload" ); @@ -2634,7 +2707,8 @@ bool CScriptConvarAccessor::Init() BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptConvarAccessor, "CConvars", SCRIPT_SINGLETON "Provides an interface to convars." ) DEFINE_SCRIPTFUNC( RegisterConvar, "register a new console variable." ) DEFINE_SCRIPTFUNC( RegisterCommand, "register a console command." ) - DEFINE_SCRIPTFUNC( SetCompletionCallback, "callback is called with 3 parameters (cmdname, partial, commands), user strings must be appended to 'commands' array" ) + DEFINE_SCRIPTFUNC( SetCompletionCallback, "callback is called with 3 parameters (cmd, partial, commands), user strings must be appended to 'commands' array" ) + DEFINE_SCRIPTFUNC( SetChangeCallback, "callback is called with 5 parameters (var, szOldValue, flOldValue, szNewValue, flNewValue)" ) DEFINE_SCRIPTFUNC( UnregisterCommand, "unregister a console command." ) DEFINE_SCRIPTFUNC( GetCommandClient, "returns the player who issued this console command." ) #ifdef GAME_DLL @@ -2671,9 +2745,6 @@ END_SCRIPTDESC(); class CEffectsScriptHelper { -private: - C_RecipientFilter filter; - public: void DynamicLight( int index, const Vector& origin, int r, int g, int b, int exponent, float radius, float die, float decay, int style = 0, int flags = 0 ) @@ -2694,6 +2765,7 @@ class CEffectsScriptHelper void Explosion( const Vector& pos, float scale, int radius, int magnitude, int flags ) { + C_RecipientFilter filter; filter.AddAllPlayers(); // framerate, modelindex, normal and materialtype are unused // radius for ragdolls @@ -2803,7 +2875,150 @@ BEGIN_SCRIPTDESC_ROOT_NAMED( CEffectsScriptHelper, "CEffects", SCRIPT_SINGLETON DEFINE_SCRIPTFUNC( Sprite, "" ) DEFINE_SCRIPTFUNC( ClientProjectile, "" ) END_SCRIPTDESC(); -#endif + + + +//============================================================================= +//============================================================================= + +extern CGlowObjectManager g_GlowObjectManager; + +class CScriptGlowObjectManager : public CAutoGameSystem +{ +public: + CUtlVector m_RegisteredObjects; + + void LevelShutdownPostEntity() + { + FOR_EACH_VEC( m_RegisteredObjects, i ) + g_GlowObjectManager.UnregisterGlowObject( m_RegisteredObjects[i] ); + m_RegisteredObjects.Purge(); + } + +public: + int Register( HSCRIPT hEntity, int r, int g, int b, int a, bool bRenderWhenOccluded, bool bRenderWhenUnoccluded ) + { + Vector vGlowColor; + vGlowColor.x = r * ( 1.0f / 255.0f ); + vGlowColor.y = g * ( 1.0f / 255.0f ); + vGlowColor.z = b * ( 1.0f / 255.0f ); + float flGlowAlpha = a * ( 1.0f / 255.0f ); + int idx = g_GlowObjectManager.RegisterGlowObject( ToEnt(hEntity), vGlowColor, flGlowAlpha, bRenderWhenOccluded, bRenderWhenUnoccluded, -1 ); + m_RegisteredObjects.AddToTail( idx ); + return idx; + } + + void Unregister( int nGlowObjectHandle ) + { + if ( (nGlowObjectHandle < 0) || (nGlowObjectHandle >= g_GlowObjectManager.m_GlowObjectDefinitions.Count()) ) + return; + g_GlowObjectManager.UnregisterGlowObject( nGlowObjectHandle ); + m_RegisteredObjects.FindAndFastRemove( nGlowObjectHandle ); + } + + void SetEntity( int nGlowObjectHandle, HSCRIPT hEntity ) + { + g_GlowObjectManager.SetEntity( nGlowObjectHandle, ToEnt(hEntity) ); + } + + void SetColor( int nGlowObjectHandle, int r, int g, int b ) + { + Vector vGlowColor; + vGlowColor.x = r * ( 1.0f / 255.0f ); + vGlowColor.y = g * ( 1.0f / 255.0f ); + vGlowColor.z = b * ( 1.0f / 255.0f ); + g_GlowObjectManager.SetColor( nGlowObjectHandle, vGlowColor ); + } + + void SetAlpha( int nGlowObjectHandle, int a ) + { + float flGlowAlpha = a * ( 1.0f / 255.0f ); + g_GlowObjectManager.SetAlpha( nGlowObjectHandle, flGlowAlpha ); + } + + void SetRenderFlags( int nGlowObjectHandle, bool bRenderWhenOccluded, bool bRenderWhenUnoccluded ) + { + g_GlowObjectManager.SetRenderFlags( nGlowObjectHandle, bRenderWhenOccluded, bRenderWhenUnoccluded ); + } + +} g_ScriptGlowObjectManager; + +BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptGlowObjectManager, "CGlowObjectManager", SCRIPT_SINGLETON "" ) + DEFINE_SCRIPTFUNC( Register, "( HSCRIPT hEntity, int r, int g, int b, int a, bool bRenderWhenOccluded, bool bRenderWhenUnoccluded )" ) + DEFINE_SCRIPTFUNC( Unregister, "" ) + DEFINE_SCRIPTFUNC( SetEntity, "" ) + DEFINE_SCRIPTFUNC( SetColor, "" ) + DEFINE_SCRIPTFUNC( SetAlpha, "" ) + DEFINE_SCRIPTFUNC( SetRenderFlags, "" ) +END_SCRIPTDESC(); + + +//============================================================================= +//============================================================================= + + +#if !defined(NO_STEAM) +class CScriptSteamAPI +{ +public: + int GetSecondsSinceComputerActive() + { + if ( !steamapicontext || !steamapicontext->SteamUtils() ) + return 0; + + return steamapicontext->SteamUtils()->GetSecondsSinceComputerActive(); + } + + int GetCurrentBatteryPower() + { + if ( !steamapicontext || !steamapicontext->SteamUtils() ) + return 0; + + return steamapicontext->SteamUtils()->GetCurrentBatteryPower(); + } + + const char *GetIPCountry() + { + if ( !steamapicontext || !steamapicontext->SteamUtils() ) + return NULL; + + const char *get = steamapicontext->SteamUtils()->GetIPCountry(); + if ( !get ) + return NULL; + + static char ret[3]; + V_strncpy( ret, get, 3 ); + + return ret; + } + + const char *GetCurrentGameLanguage() + { + if ( !steamapicontext || !steamapicontext->SteamApps() ) + return NULL; + + const char *lang = steamapicontext->SteamApps()->GetCurrentGameLanguage(); + if ( !lang ) + return NULL; + + static char ret[16]; + V_strncpy( ret, lang, sizeof(ret) ); + + return ret; + } + +} g_ScriptSteamAPI; + +BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptSteamAPI, "CSteamAPI", SCRIPT_SINGLETON "" ) + //DEFINE_SCRIPTFUNC( IsVACBanned, "" ) + DEFINE_SCRIPTFUNC( GetSecondsSinceComputerActive, "Returns the number of seconds since the user last moved the mouse." ) + DEFINE_SCRIPTFUNC( GetCurrentBatteryPower, "Return the amount of battery power left in the current system in % [0..100], 255 for being on AC power" ) + //DEFINE_SCRIPTFUNC( GetIPCountry, "Returns the 2 digit ISO 3166-1-alpha-2 format country code this client is running in (as looked up via an IP-to-location database)" ) + DEFINE_SCRIPTFUNC( GetCurrentGameLanguage, "Gets the current language that the user has set as API language code. This falls back to the Steam UI language if the user hasn't explicitly picked a language for the title." ) +END_SCRIPTDESC(); +#endif // !NO_STEAM + +#endif // CLIENT_DLL void RegisterScriptSingletons() @@ -2831,6 +3046,11 @@ void RegisterScriptSingletons() g_pScriptVM->RegisterInstance( &g_ScriptConvarAccessor, "Convars" ); #ifdef CLIENT_DLL g_pScriptVM->RegisterInstance( &g_ScriptEffectsHelper, "effects" ); + g_pScriptVM->RegisterInstance( &g_ScriptGlowObjectManager, "GlowObjectManager" ); + +#if !defined(NO_STEAM) + g_pScriptVM->RegisterInstance( &g_ScriptSteamAPI, "steam" ); +#endif #endif // Singletons not unique to VScript (not declared or defined here) diff --git a/sp/src/tier1/convar.cpp b/sp/src/tier1/convar.cpp index c49a6efbc4..fc27eb74e0 100644 --- a/sp/src/tier1/convar.cpp +++ b/sp/src/tier1/convar.cpp @@ -688,7 +688,10 @@ ConVar::~ConVar( void ) //----------------------------------------------------------------------------- void ConVar::InstallChangeCallback( FnChangeCallback_t callback ) { +#ifndef MAPBASE_VSCRIPT Assert( !m_pParent->m_fnChangeCallback || !callback ); +#endif + m_pParent->m_fnChangeCallback = callback; if ( m_pParent->m_fnChangeCallback ) From d7a06e863e86be9f6d58ac4caf681342f56787bd Mon Sep 17 00:00:00 2001 From: samisalreadytaken <46823719+samisalreadytaken@users.noreply.github.com> Date: Sun, 18 Apr 2021 18:43:05 +0200 Subject: [PATCH 2/2] Fix ScriptContextThink precision errors --- sp/src/game/client/c_baseentity.h | 9 +- sp/src/game/server/baseentity.h | 11 +- sp/src/game/shared/baseentity_shared.cpp | 160 ++++++++++------------- 3 files changed, 79 insertions(+), 101 deletions(-) diff --git a/sp/src/game/client/c_baseentity.h b/sp/src/game/client/c_baseentity.h index dabfbbd9d6..396cd3f0da 100644 --- a/sp/src/game/client/c_baseentity.h +++ b/sp/src/game/client/c_baseentity.h @@ -164,10 +164,9 @@ struct thinkfunc_t #ifdef MAPBASE_VSCRIPT struct scriptthinkfunc_t { - int m_nNextThinkTick; - HSCRIPT m_hfnThink; - unsigned short m_iContextHash; - bool m_bNoParam; + float m_flNextThink; + HSCRIPT m_hfnThink; + unsigned m_iContextHash; }; #endif @@ -295,6 +294,8 @@ class C_BaseEntity : public IClientEntity string_t m_iszScriptId; #ifdef MAPBASE_VSCRIPT CScriptScope m_ScriptScope; + + static ScriptHook_t g_Hook_UpdateOnRemove; #endif // IClientUnknown overrides. diff --git a/sp/src/game/server/baseentity.h b/sp/src/game/server/baseentity.h index a96d443bdd..fc8d232e24 100644 --- a/sp/src/game/server/baseentity.h +++ b/sp/src/game/server/baseentity.h @@ -341,10 +341,10 @@ struct thinkfunc_t #ifdef MAPBASE_VSCRIPT struct scriptthinkfunc_t { - int m_nNextThinkTick; - HSCRIPT m_hfnThink; - unsigned short m_iContextHash; - bool m_bNoParam; + float m_flNextThink; + HSCRIPT m_hfnThink; + unsigned m_iContextHash; + bool m_bNoParam; }; #endif @@ -2115,6 +2115,9 @@ class CBaseEntity : public IServerEntity int ScriptGetMoveType() { return GetMoveType(); } void ScriptSetMoveType( int iMoveType ) { SetMoveType( (MoveType_t)iMoveType ); } + int ScriptGetSolid() { return GetSolid(); } + void ScriptSetSolid( int i ) { SetSolid( (SolidType_t)i ); } + bool ScriptDispatchInteraction( int interactionType, HSCRIPT data, HSCRIPT sourceEnt ); int ScriptGetTakeDamage() { return m_takedamage; } diff --git a/sp/src/game/shared/baseentity_shared.cpp b/sp/src/game/shared/baseentity_shared.cpp index cae3f5d92f..207f454411 100644 --- a/sp/src/game/shared/baseentity_shared.cpp +++ b/sp/src/game/shared/baseentity_shared.cpp @@ -2713,13 +2713,20 @@ HSCRIPT CBaseEntity::ScriptGetPhysicsObject( void ) return NULL; } + +#ifdef GAME_DLL +#define SCRIPT_NEVER_THINK TICK_NEVER_THINK +#else +#define SCRIPT_NEVER_THINK CLIENT_THINK_NEVER +#endif + static inline void ScriptStopContextThink( scriptthinkfunc_t *context ) { Assert( context->m_hfnThink ); + Assert( context->m_flNextThink == SCRIPT_NEVER_THINK ); g_pScriptVM->ReleaseScript( context->m_hfnThink ); context->m_hfnThink = NULL; - //context->m_nNextThinkTick = TICK_NEVER_THINK; } //----------------------------------------------------------------------------- @@ -2728,55 +2735,56 @@ static inline void ScriptStopContextThink( scriptthinkfunc_t *context ) void CBaseEntity::ScriptContextThink() { float flNextThink = FLT_MAX; - int nScheduledTick = 0; + float flScheduled = 0.0f; for ( int i = 0; i < m_ScriptThinkFuncs.Count(); ++i ) { scriptthinkfunc_t *cur = m_ScriptThinkFuncs[i]; - if ( cur->m_nNextThinkTick == TICK_NEVER_THINK ) + if ( cur->m_flNextThink == SCRIPT_NEVER_THINK ) { continue; } - if ( cur->m_nNextThinkTick > gpGlobals->tickcount ) + if ( cur->m_flNextThink > gpGlobals->curtime ) { - // There is more to execute, don't stop thinking if the rest are done. - - // Find the shortest schedule - if ( !nScheduledTick || nScheduledTick > cur->m_nNextThinkTick ) + if ( ( flScheduled == 0.0f ) || ( flScheduled > cur->m_flNextThink ) ) { - nScheduledTick = cur->m_nNextThinkTick; + flScheduled = cur->m_flNextThink; } continue; } #ifdef _DEBUG // going to run the script func - cur->m_nNextThinkTick = 0; + cur->m_flNextThink = 0; #endif ScriptVariant_t varReturn; +#ifndef CLIENT_DLL if ( !cur->m_bNoParam ) { +#endif ScriptVariant_t arg = m_hScriptInstance; if ( g_pScriptVM->ExecuteFunction( cur->m_hfnThink, &arg, 1, &varReturn, NULL, true ) == SCRIPT_ERROR ) { - cur->m_nNextThinkTick = TICK_NEVER_THINK; + cur->m_flNextThink = SCRIPT_NEVER_THINK; continue; } +#ifndef CLIENT_DLL } else { if ( g_pScriptVM->ExecuteFunction( cur->m_hfnThink, NULL, 0, &varReturn, NULL, true ) == SCRIPT_ERROR ) { - cur->m_nNextThinkTick = TICK_NEVER_THINK; + cur->m_flNextThink = SCRIPT_NEVER_THINK; continue; } } +#endif - if ( cur->m_nNextThinkTick == TICK_NEVER_THINK ) + if ( cur->m_flNextThink == SCRIPT_NEVER_THINK ) { // stopped from script while thinking continue; @@ -2785,13 +2793,13 @@ void CBaseEntity::ScriptContextThink() float flReturn; if ( !varReturn.AssignTo( &flReturn ) ) { - cur->m_nNextThinkTick = TICK_NEVER_THINK; + cur->m_flNextThink = SCRIPT_NEVER_THINK; continue; } if ( flReturn < 0.0f ) { - cur->m_nNextThinkTick = TICK_NEVER_THINK; + cur->m_flNextThink = SCRIPT_NEVER_THINK; continue; } @@ -2800,95 +2808,60 @@ void CBaseEntity::ScriptContextThink() flNextThink = flReturn; } - cur->m_nNextThinkTick = TIME_TO_TICKS( gpGlobals->curtime + flReturn ); + cur->m_flNextThink = gpGlobals->curtime + flReturn - 0.001; } // deferred safe removal for ( int i = 0; i < m_ScriptThinkFuncs.Count(); ) { - if ( m_ScriptThinkFuncs[i]->m_nNextThinkTick == TICK_NEVER_THINK ) + scriptthinkfunc_t *cur = m_ScriptThinkFuncs[i]; + if ( cur->m_flNextThink == SCRIPT_NEVER_THINK ) { - ScriptStopContextThink( m_ScriptThinkFuncs[i] ); - delete m_ScriptThinkFuncs[i]; + ScriptStopContextThink( cur ); + delete cur; m_ScriptThinkFuncs.Remove(i); } else ++i; } - bool bNewNext = flNextThink < FLT_MAX; - -#ifdef _DEBUG -#ifdef GAME_DLL - int nNextThinkTick = GetNextThinkTick("ScriptContextThink"); // -1 -#else - int nNextThinkTick = GetNextThinkTick(); // 0 -#endif - if ( ( nNextThinkTick <= 0 ) || ( nNextThinkTick >= nScheduledTick ) || ( nNextThinkTick == gpGlobals->tickcount ) ) + if ( flNextThink < FLT_MAX ) { -#endif - if ( nScheduledTick ) + if ( flScheduled > 0.0f ) { - float flScheduledTime = TICKS_TO_TIME( nScheduledTick ); - - if ( bNewNext ) - { - flNextThink = min( gpGlobals->curtime + flNextThink, flScheduledTime ); - } - else - { - flNextThink = flScheduledTime; - } + flNextThink = min( gpGlobals->curtime + flNextThink, flScheduled ); } else { - if ( bNewNext ) - { - flNextThink = gpGlobals->curtime + flNextThink; - } - else - { -#ifdef GAME_DLL - flNextThink = TICK_NEVER_THINK; -#else - flNextThink = CLIENT_THINK_NEVER; -#endif - } + flNextThink = gpGlobals->curtime + flNextThink; } -#ifdef _DEBUG } else { - // Next think was set (from script) to a sooner tick while thinking? - Assert(0); - - if ( nScheduledTick ) + if ( flScheduled > 0.0f ) { - int nNextSchedule = min( nScheduledTick, nNextThinkTick ); - float flNextSchedule = TICKS_TO_TIME( nNextSchedule ); - - if ( bNewNext ) - { - flNextThink = min( gpGlobals->curtime + flNextThink, flNextSchedule ); - } - else - { - flNextThink = flNextSchedule; - } + flNextThink = flScheduled; } else { - float nextthink = TICKS_TO_TIME( nNextThinkTick ); - - if ( bNewNext ) - { - flNextThink = min( gpGlobals->curtime + flNextThink, nextthink ); - } - else - { - flNextThink = nextthink; - } + flNextThink = SCRIPT_NEVER_THINK; } } + +#ifdef _DEBUG +#ifdef GAME_DLL + int nNextThinkTick = GetNextThinkTick("ScriptContextThink"); + float flNextThinkTime = TICKS_TO_TIME(nNextThinkTick); + + // If internal next think tick is earlier than what we have here with flNextThink, + // whoever set that think may fail. In worst case scenario the entity may stop thinking. + if ( nNextThinkTick > gpGlobals->tickcount ) + { + if ( flNextThink == SCRIPT_NEVER_THINK ) + Assert(0); + if ( flNextThinkTime < flNextThink ) + Assert(0); + } +#endif #endif #ifdef GAME_DLL @@ -2898,8 +2871,10 @@ void CBaseEntity::ScriptContextThink() #endif } +#ifndef CLIENT_DLL // see ScriptSetThink static bool s_bScriptContextThinkNoParam = false; +#endif //----------------------------------------------------------------------------- // @@ -2917,7 +2892,7 @@ void CBaseEntity::ScriptSetContextThink( const char* szContext, HSCRIPT hFunc, f #endif scriptthinkfunc_t *pf = NULL; - unsigned short hash = ( szContext && *szContext ) ? HashString( szContext ) : 0; + unsigned hash = szContext ? HashString( szContext ) : 0; FOR_EACH_VEC( m_ScriptThinkFuncs, i ) { @@ -2939,14 +2914,16 @@ void CBaseEntity::ScriptSetContextThink( const char* szContext, HSCRIPT hFunc, f m_ScriptThinkFuncs.SetGrowSize(1); m_ScriptThinkFuncs.AddToTail( pf ); - pf->m_bNoParam = s_bScriptContextThinkNoParam; pf->m_iContextHash = hash; +#ifndef CLIENT_DLL + pf->m_bNoParam = s_bScriptContextThinkNoParam; +#endif } // update existing else { #ifdef _DEBUG - if ( pf->m_nNextThinkTick == 0 ) + if ( pf->m_flNextThink == 0 ) { Warning("Script think ('%s') was changed while it was thinking!\n", szContext); } @@ -2957,31 +2934,29 @@ void CBaseEntity::ScriptSetContextThink( const char* szContext, HSCRIPT hFunc, f float nextthink = gpGlobals->curtime + flTime; pf->m_hfnThink = hFunc; - pf->m_nNextThinkTick = TIME_TO_TICKS( nextthink ); + pf->m_flNextThink = nextthink; #ifdef GAME_DLL int nexttick = GetNextThinkTick( RegisterThinkContext( "ScriptContextThink" ) ); -#else - int nexttick = GetNextThinkTick(); -#endif - - // sooner than next think - if ( nexttick <= 0 || nexttick > pf->m_nNextThinkTick ) + if ( nexttick <= 0 || TICKS_TO_TIME(nexttick) > nextthink ) { -#ifdef GAME_DLL SetContextThink( &CBaseEntity::ScriptContextThink, nextthink, "ScriptContextThink" ); + } #else - SetNextClientThink( nextthink ); -#endif + { + // let it self adjust + SetNextClientThink( gpGlobals->curtime ); } +#endif } // null func input, think exists else if ( pf ) { - pf->m_nNextThinkTick = TICK_NEVER_THINK; + pf->m_flNextThink = SCRIPT_NEVER_THINK; } } +#ifndef CLIENT_DLL //----------------------------------------------------------------------------- // m_bNoParam and s_bScriptContextThinkNoParam exist only to keep backwards compatibility // and are an alternative to this script closure: @@ -2991,7 +2966,6 @@ void CBaseEntity::ScriptSetContextThink( const char* szContext, HSCRIPT hFunc, f // SetContextThink( "", function(_){ return func() }, time ) // } //----------------------------------------------------------------------------- -#ifndef CLIENT_DLL void CBaseEntity::ScriptSetThink( HSCRIPT hFunc, float time ) { s_bScriptContextThinkNoParam = true;