diff --git a/sp/src/game/client/c_baseplayer.cpp b/sp/src/game/client/c_baseplayer.cpp index c12e25f8..e47f6de8 100644 --- a/sp/src/game/client/c_baseplayer.cpp +++ b/sp/src/game/client/c_baseplayer.cpp @@ -492,14 +492,14 @@ C_BasePlayer::~C_BasePlayer() if ( this == s_pLocalPlayer ) { s_pLocalPlayer = NULL; - } #ifdef MAPBASE_VSCRIPT - if ( IsLocalPlayer() && g_pScriptVM ) - { - g_pScriptVM->SetValue( "player", SCRIPT_VARIANT_NULL ); - } + if ( g_pScriptVM ) + { + g_pScriptVM->SetValue( "player", SCRIPT_VARIANT_NULL ); + } #endif + } delete m_pFlashlight; } diff --git a/sp/src/game/client/vscript_client.cpp b/sp/src/game/client/vscript_client.cpp index 3f7e7cea..dc53cc8c 100644 --- a/sp/src/game/client/vscript_client.cpp +++ b/sp/src/game/client/vscript_client.cpp @@ -20,6 +20,7 @@ #include "proxyentity.h" #include "materialsystem/imaterial.h" #include "materialsystem/imaterialvar.h" +#include "mapbase/vscript_singletons.h" #endif extern IScriptManager *scriptmanager; @@ -46,6 +47,11 @@ extern ScriptClassDesc_t * GetScriptDesc( CBaseEntity * ); class CScriptClientEntityIterator { public: + HSCRIPT GetLocalPlayer() + { + return ToHScript( C_BasePlayer::GetLocalPlayer() ); + } + HSCRIPT First() { return Next(NULL); } HSCRIPT Next( HSCRIPT hStartEntity ) @@ -94,6 +100,7 @@ private: } g_ScriptEntityIterator; BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptClientEntityIterator, "CEntities", SCRIPT_SINGLETON "The global list of entities" ) + DEFINE_SCRIPTFUNC( GetLocalPlayer, "Get local player" ) DEFINE_SCRIPTFUNC( First, "Begin an iteration over the list of entities" ) DEFINE_SCRIPTFUNC( Next, "Continue an iteration over the list of entities, providing reference to a previously found entity" ) DEFINE_SCRIPTFUNC( CreateByClassname, "Creates an entity by classname" ) @@ -399,7 +406,7 @@ void CScriptMaterialProxy::SetVarVector( int i, const Vector &value ) } EXPOSE_INTERFACE( CScriptMaterialProxy, IMaterialProxy, "VScriptProxy" IMATERIAL_PROXY_INTERFACE_VERSION ); -#endif +#endif // MAPBASE_VSCRIPT //----------------------------------------------------------------------------- // @@ -431,6 +438,39 @@ bool DoIncludeScript( const char *pszScript, HSCRIPT hScope ) return true; } +#ifdef MAPBASE_VSCRIPT +static bool Con_IsVisible() +{ + return engine->Con_IsVisible(); +} + +static bool IsWindowedMode() +{ + return engine->IsWindowedMode(); +} + +int ScreenTransform( const Vector& point, Vector& screen ); + +//----------------------------------------------------------------------------- +// Input array [x,y], set normalised screen space pos. Return true if on screen +//----------------------------------------------------------------------------- +static bool ScriptScreenTransform( const Vector &pos, HSCRIPT hArray ) +{ + if ( g_pScriptVM->GetNumTableEntries(hArray) >= 2 ) + { + Vector v; + bool r = ScreenTransform( pos, v ); + float x = 0.5f * ( 1.0f + v[0] ); + float y = 0.5f * ( 1.0f - v[1] ); + + g_pScriptVM->SetValue( hArray, ScriptVariant_t(0), x ); + g_pScriptVM->SetValue( hArray, 1, y ); + return !r; + } + return false; +} +#endif + bool VScriptClientInit() { VMPROF_START @@ -487,14 +527,30 @@ bool VScriptClientInit() if( g_pScriptVM ) { #ifdef MAPBASE_VSCRIPT + // Moved here from LevelInitPostEntity, which is executed before local player is spawned. + // This is executed after C_World::OnDataChanged, which is after C_BasePlayer::Spawn + if ( C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer() ) + { + g_pScriptVM->SetValue( "player", pPlayer->GetScriptInstance() ); + } + CGMsg( 0, CON_GROUP_VSCRIPT, "VSCRIPT CLIENT: Started VScript virtual machine using script language '%s'\n", g_pScriptVM->GetLanguageName() ); #else Log( "VSCRIPT: Started VScript virtual machine using script language '%s'\n", g_pScriptVM->GetLanguageName() ); #endif ScriptRegisterFunction( g_pScriptVM, GetMapName, "Get the name of the map."); ScriptRegisterFunction( g_pScriptVM, Time, "Get the current server time" ); + ScriptRegisterFunction( g_pScriptVM, DoUniqueString, SCRIPT_ALIAS( "UniqueString", "Generate a string guaranteed to be unique across the life of the script VM, with an optional root string." ) ); ScriptRegisterFunction( g_pScriptVM, DoIncludeScript, "Execute a script (internal)" ); - +#ifdef MAPBASE_VSCRIPT + ScriptRegisterFunction( g_pScriptVM, Con_IsVisible, "Returns true if the console is visible" ); + ScriptRegisterFunction( g_pScriptVM, ScreenWidth, "Width of the screen in pixels" ); + ScriptRegisterFunction( g_pScriptVM, ScreenHeight, "Height of the screen in pixels" ); + ScriptRegisterFunction( g_pScriptVM, IsWindowedMode, "" ); + ScriptRegisterFunctionNamed( g_pScriptVM, ScriptScreenTransform, "ScreenTransform", "Get the x & y positions of a world position in screen space. Returns true if it's onscreen" ); +#endif + + if ( GameRules() ) { GameRules()->RegisterScriptFunctions(); @@ -519,6 +575,7 @@ bool VScriptClientInit() g_pScriptVM->Run( g_Script_vscript_client ); } + VScriptRunScript( "vscript_client", true ); VScriptRunScript( "mapspawn", false ); VMPROF_SHOW( pszScriptLanguage, "virtual machine startup" ); @@ -579,20 +636,13 @@ public: virtual void LevelInitPostEntity( void ) { m_bAllowEntityCreationInScripts = false; -#ifdef MAPBASE_VSCRIPT - if (g_pScriptVM) - { - C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); - if (pPlayer) - { - g_pScriptVM->SetValue( "player", pPlayer->GetScriptInstance() ); - } - } -#endif } virtual void LevelShutdownPostEntity( void ) { +#ifdef MAPBASE_VSCRIPT + g_ScriptNetMsg->LevelShutdownPreVM(); +#endif VScriptClientTerm(); } diff --git a/sp/src/game/server/baseentity.cpp b/sp/src/game/server/baseentity.cpp index 3cca68f5..66940c08 100644 --- a/sp/src/game/server/baseentity.cpp +++ b/sp/src/game/server/baseentity.cpp @@ -2190,7 +2190,7 @@ BEGIN_DATADESC_NO_BASE( CBaseEntity ) DEFINE_THINKFUNC( ShadowCastDistThink ), DEFINE_THINKFUNC( ScriptThink ), #ifdef MAPBASE_VSCRIPT - DEFINE_THINKFUNC( ScriptThinkH ), + DEFINE_THINKFUNC( ScriptContextThink ), #endif #ifdef MAPBASE @@ -2442,6 +2442,7 @@ BEGIN_ENT_SCRIPTDESC_ROOT( CBaseEntity, "Root class of all server-side entities" #ifdef MAPBASE_VSCRIPT DEFINE_SCRIPTFUNC_NAMED( ScriptSetThinkFunction, "SetThinkFunction", "" ) DEFINE_SCRIPTFUNC_NAMED( ScriptStopThinkFunction, "StopThinkFunction", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptSetContextThink, "SetContextThink", "Set a think function on this entity." ) DEFINE_SCRIPTFUNC_NAMED( ScriptSetThink, "SetThink", "" ) DEFINE_SCRIPTFUNC_NAMED( ScriptStopThink, "StopThink", "" ) @@ -2590,11 +2591,12 @@ void CBaseEntity::UpdateOnRemove( void ) m_hScriptInstance = NULL; #ifdef MAPBASE_VSCRIPT - if ( m_hfnThink ) + FOR_EACH_VEC( m_ScriptThinkFuncs, i ) { - g_pScriptVM->ReleaseScript( m_hfnThink ); - m_hfnThink = NULL; + HSCRIPT h = m_ScriptThinkFuncs[i].m_hfnThink; + if ( h ) g_pScriptVM->ReleaseScript( h ); } + m_ScriptThinkFuncs.Purge(); #endif // MAPBASE_VSCRIPT } } @@ -8653,60 +8655,172 @@ void CBaseEntity::ScriptStopThinkFunction() SetContextThink( NULL, TICK_NEVER_THINK, "ScriptThink" ); } -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -void CBaseEntity::ScriptThinkH() + +static inline void ScriptStopContextThink( scriptthinkfunc_t *context ) { - ScriptVariant_t varThinkRetVal; - if ( g_pScriptVM->ExecuteFunction(m_hfnThink, NULL, 0, &varThinkRetVal, NULL, true) == SCRIPT_ERROR ) - { - DevWarning("%s FAILED to call script think function (invalid closure)!\n", GetDebugName()); - ScriptStopThink(); - return; - } - - float flThinkFrequency = 0.f; - if ( !varThinkRetVal.AssignTo(&flThinkFrequency) ) - { - // no return value stops thinking - ScriptStopThink(); - return; - } - - SetNextThink( gpGlobals->curtime + flThinkFrequency, "ScriptThinkH" ); + g_pScriptVM->ReleaseScript( context->m_hfnThink ); + context->m_hfnThink = NULL; + context->m_nNextThinkTick = TICK_NEVER_THINK; } -void CBaseEntity::ScriptSetThink( HSCRIPT hFunc, float flTime ) +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CBaseEntity::ScriptContextThink() { - if ( hFunc ) + float flNextThink = FLT_MAX; + int nScheduledTick = 0; + + for ( int i = m_ScriptThinkFuncs.Count(); i--; ) { - if ( m_hfnThink ) + scriptthinkfunc_t *cur = &m_ScriptThinkFuncs[i]; + + if ( cur->m_nNextThinkTick == TICK_NEVER_THINK ) + continue; + + if ( cur->m_nNextThinkTick > gpGlobals->tickcount ) { - // release old func - ScriptStopThink(); + // There is more to execute, don't stop thinking if the rest are done. + + // also find the shortest schedule + if ( !nScheduledTick || nScheduledTick > cur->m_nNextThinkTick ) + { + nScheduledTick = cur->m_nNextThinkTick; + } + continue; } - // no type check here, print error on call instead - m_hfnThink = hFunc; + ScriptVariant_t varReturn; - flTime = max( 0, flTime ); - SetContextThink( &CBaseEntity::ScriptThinkH, gpGlobals->curtime + flTime, "ScriptThinkH" ); + if ( cur->m_bNoParam ) + { + if ( g_pScriptVM->Call( cur->m_hfnThink, NULL, true, &varReturn ) == SCRIPT_ERROR ) + { + ScriptStopContextThink(cur); + m_ScriptThinkFuncs.Remove(i); + continue; + } + } + else + { + if ( g_pScriptVM->Call( cur->m_hfnThink, NULL, true, &varReturn, m_hScriptInstance ) == SCRIPT_ERROR ) + { + ScriptStopContextThink(cur); + m_ScriptThinkFuncs.Remove(i); + continue; + } + } + + float flReturn; + if ( !varReturn.AssignTo( &flReturn ) ) + { + ScriptStopContextThink(cur); + m_ScriptThinkFuncs.Remove(i); + continue; + } + + if ( flReturn < 0.0f ) + { + ScriptStopContextThink(cur); + m_ScriptThinkFuncs.Remove(i); + continue; + } + + // find the shortest delay + if ( flReturn < flNextThink ) + { + flNextThink = flReturn; + } + + cur->m_nNextThinkTick = TIME_TO_TICKS( gpGlobals->curtime + flReturn ); + } + + if ( flNextThink < FLT_MAX ) + { + SetNextThink( gpGlobals->curtime + flNextThink, "ScriptContextThink" ); + } + else if ( nScheduledTick ) + { + SetNextThink( TICKS_TO_TIME( nScheduledTick ), "ScriptContextThink" ); } else { - ScriptStopThink(); + SetNextThink( TICK_NEVER_THINK, "ScriptContextThink" ); } } +// see ScriptSetThink +static bool s_bScriptContextThinkNoParam = false; + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CBaseEntity::ScriptSetContextThink( const char* szContext, HSCRIPT hFunc, float flTime ) +{ + scriptthinkfunc_t th; + V_memset( &th, 0x0, sizeof(scriptthinkfunc_t) ); + unsigned short hash = ( szContext && *szContext ) ? HashString( szContext ) : 0; + bool bFound = false; + + FOR_EACH_VEC( m_ScriptThinkFuncs, i ) + { + scriptthinkfunc_t f = m_ScriptThinkFuncs[i]; + if ( hash == f.m_iContextHash ) + { + th = f; + m_ScriptThinkFuncs.Remove(i); // reorder + bFound = true; + break; + } + } + + if ( hFunc ) + { + float nextthink = gpGlobals->curtime + flTime; + + th.m_bNoParam = s_bScriptContextThinkNoParam; + th.m_hfnThink = hFunc; + th.m_iContextHash = hash; + th.m_nNextThinkTick = TIME_TO_TICKS( nextthink ); + + m_ScriptThinkFuncs.AddToHead( th ); + + int nexttick = GetNextThinkTick( RegisterThinkContext( "ScriptContextThink" ) ); + + // sooner than next think + if ( nexttick <= 0 || nexttick > th.m_nNextThinkTick ) + { + SetContextThink( &CBaseEntity::ScriptContextThink, nextthink, "ScriptContextThink" ); + } + } + // null func input, think exists + else if ( bFound ) + { + ScriptStopContextThink( &th ); + } +} + +//----------------------------------------------------------------------------- +// m_bNoParam and s_bScriptContextThinkNoParam exist only to keep backwards compatibility +// and are an alternative to this script closure: +// +// function CBaseEntity::SetThink( func, time ) +// { +// SetContextThink( "", function(_){ return func() }, time ) +// } +//----------------------------------------------------------------------------- +void CBaseEntity::ScriptSetThink( HSCRIPT hFunc, float time ) +{ + s_bScriptContextThinkNoParam = true; + ScriptSetContextThink( NULL, hFunc, time ); + s_bScriptContextThinkNoParam = false; +} + void CBaseEntity::ScriptStopThink() { - if (m_hfnThink) - { - g_pScriptVM->ReleaseScript(m_hfnThink); - m_hfnThink = NULL; - } - SetContextThink( NULL, TICK_NEVER_THINK, "ScriptThinkH" ); + ScriptSetContextThink( NULL, NULL, 0.0f ); } + #endif // MAPBASE_VSCRIPT //----------------------------------------------------------------------------- diff --git a/sp/src/game/server/baseentity.h b/sp/src/game/server/baseentity.h index 79731f15..c0956a87 100644 --- a/sp/src/game/server/baseentity.h +++ b/sp/src/game/server/baseentity.h @@ -338,6 +338,16 @@ struct thinkfunc_t DECLARE_SIMPLE_DATADESC(); }; +#ifdef MAPBASE_VSCRIPT +struct scriptthinkfunc_t +{ + HSCRIPT m_hfnThink; + unsigned short m_iContextHash; + int m_nNextThinkTick; + bool m_bNoParam; +}; +#endif + struct EmitSound_t; struct rotatingpushmove_t; @@ -1988,11 +1998,12 @@ public: #ifdef MAPBASE_VSCRIPT void ScriptSetThinkFunction(const char *szFunc, float time); void ScriptStopThinkFunction(); - void ScriptSetThink(HSCRIPT hFunc, float time); + void ScriptSetContextThink( const char* szContext, HSCRIPT hFunc, float time ); + void ScriptSetThink( HSCRIPT hFunc, float time ); void ScriptStopThink(); - void ScriptThinkH(); + void ScriptContextThink(); private: - HSCRIPT m_hfnThink; + CUtlVector< scriptthinkfunc_t > m_ScriptThinkFuncs; public: #endif const char* GetScriptId(); diff --git a/sp/src/game/server/cbase.cpp b/sp/src/game/server/cbase.cpp index 11365611..81050538 100644 --- a/sp/src/game/server/cbase.cpp +++ b/sp/src/game/server/cbase.cpp @@ -906,7 +906,7 @@ CEventQueue::AddEvent( CBaseEntity *target, const char *targetInput, variant_t V AddEvent( newEvent ); #ifdef MAPBASE_VSCRIPT - return reinterpret_cast(newEvent); + return reinterpret_cast(newEvent); // POINTER_TO_INT #endif } @@ -1257,7 +1257,10 @@ void ServiceEventQueue( void ) #ifdef MAPBASE_VSCRIPT //----------------------------------------------------------------------------- -// Remove events on entity by input. +// Remove pending events on entity by input. +// +// Also removes events that were targeted with their debug name (classname when unnamed). +// E.g. CancelEventsByInput( pRelay, "Trigger" ) removes all pending logic_relay "Trigger" events. //----------------------------------------------------------------------------- void CEventQueue::CancelEventsByInput( CBaseEntity *pTarget, const char *szInput ) { @@ -1292,9 +1295,6 @@ void CEventQueue::CancelEventsByInput( CBaseEntity *pTarget, const char *szInput bool CEventQueue::RemoveEvent( intptr_t event ) { - if ( !event ) - return false; - EventQueuePrioritizedEvent_t *pe = reinterpret_cast(event); // INT_TO_POINTER for ( EventQueuePrioritizedEvent_t *pCur = m_Events.m_pNext; pCur; pCur = pCur->m_pNext ) @@ -1312,9 +1312,6 @@ bool CEventQueue::RemoveEvent( intptr_t event ) float CEventQueue::GetTimeLeft( intptr_t event ) { - if ( !event ) - return 0.f; - EventQueuePrioritizedEvent_t *pe = reinterpret_cast(event); // INT_TO_POINTER for ( EventQueuePrioritizedEvent_t *pCur = m_Events.m_pNext; pCur; pCur = pCur->m_pNext ) diff --git a/sp/src/game/server/gameinterface.cpp b/sp/src/game/server/gameinterface.cpp index 6732101e..8f3df0a7 100644 --- a/sp/src/game/server/gameinterface.cpp +++ b/sp/src/game/server/gameinterface.cpp @@ -3196,7 +3196,11 @@ float CServerGameClients::ProcessUsercmds( edict_t *player, bf_read *buf, int nu for ( i = totalcmds - 1; i >= 0; i-- ) { to = &cmds[ i ]; +#if defined( MAPBASE_VSCRIPT ) + ReadUsercmd( buf, to, from, pPlayer ); // Tell whose UserCmd it is +#else ReadUsercmd( buf, to, from ); +#endif from = to; } diff --git a/sp/src/game/server/vscript_server.cpp b/sp/src/game/server/vscript_server.cpp index 63f0ac0d..60b1a873 100644 --- a/sp/src/game/server/vscript_server.cpp +++ b/sp/src/game/server/vscript_server.cpp @@ -18,6 +18,7 @@ #include "vscript_server.nut" #ifdef MAPBASE_VSCRIPT #include "world.h" +#include "mapbase/vscript_singletons.h" #endif extern ScriptClassDesc_t * GetScriptDesc( CBaseEntity * ); @@ -246,451 +247,6 @@ CScriptKeyValues::~CScriptKeyValues( ) } #endif -#ifdef MAPBASE_VSCRIPT -#define RETURN_IF_CANNOT_DRAW_OVERLAY\ - if (engine->IsPaused())\ - {\ - CGWarning( 1, CON_GROUP_VSCRIPT, "debugoverlay: cannot draw while the game is paused!\n");\ - return;\ - } -class CDebugOverlayScriptHelper -{ -public: - - void Box(const Vector &origin, const Vector &mins, const Vector &maxs, int r, int g, int b, int a, float flDuration) - { - RETURN_IF_CANNOT_DRAW_OVERLAY - - if (debugoverlay) - { - debugoverlay->AddBoxOverlay(origin, mins, maxs, vec3_angle, r, g, b, a, flDuration); - } - } - void BoxDirection(const Vector &origin, const Vector &mins, const Vector &maxs, const Vector &forward, int r, int g, int b, int a, float flDuration) - { - RETURN_IF_CANNOT_DRAW_OVERLAY - - QAngle f_angles = vec3_angle; - f_angles.y = UTIL_VecToYaw(forward); - - if (debugoverlay) - { - debugoverlay->AddBoxOverlay(origin, mins, maxs, f_angles, r, g, b, a, flDuration); - } - } - void BoxAngles(const Vector &origin, const Vector &mins, const Vector &maxs, const QAngle &angles, int r, int g, int b, int a, float flDuration) - { - RETURN_IF_CANNOT_DRAW_OVERLAY - - if (debugoverlay) - { - debugoverlay->AddBoxOverlay(origin, mins, maxs, angles, r, g, b, a, flDuration); - } - } - void SweptBox(const Vector& start, const Vector& end, const Vector& mins, const Vector& maxs, const QAngle & angles, int r, int g, int b, int a, float flDuration) - { - RETURN_IF_CANNOT_DRAW_OVERLAY - - if (debugoverlay) - { - debugoverlay->AddSweptBoxOverlay(start, end, mins, maxs, angles, r, g, b, a, flDuration); - } - } - void EntityBounds(HSCRIPT pEntity, int r, int g, int b, int a, float flDuration) - { - RETURN_IF_CANNOT_DRAW_OVERLAY - - CBaseEntity *pEnt = ToEnt(pEntity); - if (!pEnt) - return; - - const CCollisionProperty *pCollide = pEnt->CollisionProp(); - if (debugoverlay) - { - debugoverlay->AddBoxOverlay(pCollide->GetCollisionOrigin(), pCollide->OBBMins(), pCollide->OBBMaxs(), pCollide->GetCollisionAngles(), r, g, b, a, flDuration); - } - } - void Line(const Vector &origin, const Vector &target, int r, int g, int b, bool noDepthTest, float flDuration) - { - RETURN_IF_CANNOT_DRAW_OVERLAY - - if (debugoverlay) - { - debugoverlay->AddLineOverlay(origin, target, r, g, b, noDepthTest, flDuration); - } - } - void Triangle(const Vector &p1, const Vector &p2, const Vector &p3, int r, int g, int b, int a, bool noDepthTest, float duration) - { - RETURN_IF_CANNOT_DRAW_OVERLAY - - if (debugoverlay) - { - debugoverlay->AddTriangleOverlay(p1, p2, p3, r, g, b, a, noDepthTest, duration); - } - } - void EntityText(int entityID, int text_offset, const char *text, float flDuration, int r, int g, int b, int a) - { - RETURN_IF_CANNOT_DRAW_OVERLAY - - if (debugoverlay) - { - debugoverlay->AddEntityTextOverlay(entityID, text_offset, flDuration, - (int)clamp(r * 255.f, 0.f, 255.f), (int)clamp(g * 255.f, 0.f, 255.f), (int)clamp(b * 255.f, 0.f, 255.f), - (int)clamp(a * 255.f, 0.f, 255.f), text); - } - } - void EntityTextAtPosition(const Vector &origin, int text_offset, const char *text, float flDuration, int r, int g, int b, int a) - { - RETURN_IF_CANNOT_DRAW_OVERLAY - - if (debugoverlay) - { - debugoverlay->AddTextOverlayRGB(origin, text_offset, flDuration, r, g, b, a, "%s", text); - } - } - void Grid(const Vector &vPosition) - { - RETURN_IF_CANNOT_DRAW_OVERLAY - - if (debugoverlay) - { - debugoverlay->AddGridOverlay(vPosition); - } - } - void Text(const Vector &origin, const char *text, float flDuration) - { - RETURN_IF_CANNOT_DRAW_OVERLAY - - if (debugoverlay) - { - debugoverlay->AddTextOverlay(origin, flDuration, "%s", text); - } - } - void ScreenText(float fXpos, float fYpos, const char *text, int r, int g, int b, int a, float flDuration) - { - RETURN_IF_CANNOT_DRAW_OVERLAY - - if (debugoverlay) - { - debugoverlay->AddScreenTextOverlay(fXpos, fYpos, flDuration, r, g, b, a, text); - } - } - void Cross3D(const Vector &position, float size, int r, int g, int b, bool noDepthTest, float flDuration) - { - RETURN_IF_CANNOT_DRAW_OVERLAY - - Line( position + Vector(size,0,0), position - Vector(size,0,0), r, g, b, noDepthTest, flDuration ); - Line( position + Vector(0,size,0), position - Vector(0,size,0), r, g, b, noDepthTest, flDuration ); - Line( position + Vector(0,0,size), position - Vector(0,0,size), r, g, b, noDepthTest, flDuration ); - } - void Cross3DOriented(const Vector &position, const QAngle &angles, float size, int r, int g, int b, bool noDepthTest, float flDuration) - { - RETURN_IF_CANNOT_DRAW_OVERLAY - - Vector forward, right, up; - AngleVectors( angles, &forward, &right, &up ); - - forward *= size; - right *= size; - up *= size; - - Line( position + right, position - right, r, g, b, noDepthTest, flDuration ); - Line( position + forward, position - forward, r, g, b, noDepthTest, flDuration ); - Line( position + up, position - up, r, g, b, noDepthTest, flDuration ); - } - void DrawTickMarkedLine(const Vector &startPos, const Vector &endPos, float tickDist, int tickTextDist, int r, int g, int b, bool noDepthTest, float flDuration) - { - RETURN_IF_CANNOT_DRAW_OVERLAY - - Vector lineDir = (endPos - startPos); - float lineDist = VectorNormalize(lineDir); - int numTicks = lineDist / tickDist; - - Vector upVec = Vector(0,0,4); - Vector sideDir; - Vector tickPos = startPos; - int tickTextCnt = 0; - - CrossProduct(lineDir, upVec, sideDir); - - Line(startPos, endPos, r, g, b, noDepthTest, flDuration); - - for (int i = 0; i 0 ) - { - Triangle( p5, p4, p3, r, g, b, a, noDepthTest, flDuration ); - Triangle( p1, p7, p6, r, g, b, a, noDepthTest, flDuration ); - Triangle( p6, p2, p1, r, g, b, a, noDepthTest, flDuration ); - - Triangle( p3, p4, p5, r, g, b, a, noDepthTest, flDuration ); - Triangle( p6, p7, p1, r, g, b, a, noDepthTest, flDuration ); - Triangle( p1, p2, p6, r, g, b, a, noDepthTest, flDuration ); - } - } - void YawArrow(const Vector &startPos, float yaw, float length, float width, int r, int g, int b, int a, bool noDepthTest, float flDuration) - { - RETURN_IF_CANNOT_DRAW_OVERLAY - - Vector forward = UTIL_YawToVector( yaw ); - HorzArrow( startPos, startPos + forward * length, width, r, g, b, a, noDepthTest, flDuration ); - } - void VertArrow(const Vector &startPos, const Vector &endPos, float width, int r, int g, int b, int a, bool noDepthTest, float flDuration) - { - RETURN_IF_CANNOT_DRAW_OVERLAY - - Vector lineDir = (endPos - startPos); - VectorNormalize( lineDir ); - Vector upVec; - Vector sideDir; - float radius = width / 2.0; - - VectorVectors( lineDir, sideDir, upVec ); - - Vector p1 = startPos - upVec * radius; - Vector p2 = endPos - lineDir * width - upVec * radius; - Vector p3 = endPos - lineDir * width - upVec * width; - Vector p4 = endPos; - Vector p5 = endPos - lineDir * width + upVec * width; - Vector p6 = endPos - lineDir * width + upVec * radius; - Vector p7 = startPos + upVec * radius; - - Line(p1, p2, r,g,b,noDepthTest,flDuration); - Line(p2, p3, r,g,b,noDepthTest,flDuration); - Line(p3, p4, r,g,b,noDepthTest,flDuration); - Line(p4, p5, r,g,b,noDepthTest,flDuration); - Line(p5, p6, r,g,b,noDepthTest,flDuration); - Line(p6, p7, r,g,b,noDepthTest,flDuration); - - if ( a > 0 ) - { - Triangle( p5, p4, p3, r, g, b, a, noDepthTest, flDuration ); - Triangle( p1, p7, p6, r, g, b, a, noDepthTest, flDuration ); - Triangle( p6, p2, p1, r, g, b, a, noDepthTest, flDuration ); - - Triangle( p3, p4, p5, r, g, b, a, noDepthTest, flDuration ); - Triangle( p6, p7, p1, r, g, b, a, noDepthTest, flDuration ); - Triangle( p1, p2, p6, r, g, b, a, noDepthTest, flDuration ); - } - } - void Axis(const Vector &position, const QAngle &angles, float size, bool noDepthTest, float flDuration) - { - RETURN_IF_CANNOT_DRAW_OVERLAY - - Vector xvec, yvec, zvec; - AngleVectors( angles, &xvec, &yvec, &zvec ); - - xvec = position + (size * xvec); - yvec = position - (size * yvec); - zvec = position + (size * zvec); - - Line( position, xvec, 255, 0, 0, noDepthTest, flDuration ); - Line( position, yvec, 0, 255, 0, noDepthTest, flDuration ); - Line( position, zvec, 0, 0, 255, noDepthTest, flDuration ); - } - void Sphere(const Vector ¢er, float radius, int r, int g, int b, bool noDepthTest, float flDuration) - { - RETURN_IF_CANNOT_DRAW_OVERLAY - - Vector edge, lastEdge; - - float axisSize = radius; - Line( center + Vector( 0, 0, -axisSize ), center + Vector( 0, 0, axisSize ), r, g, b, noDepthTest, flDuration ); - Line( center + Vector( 0, -axisSize, 0 ), center + Vector( 0, axisSize, 0 ), r, g, b, noDepthTest, flDuration ); - Line( center + Vector( -axisSize, 0, 0 ), center + Vector( axisSize, 0, 0 ), r, g, b, noDepthTest, flDuration ); - - lastEdge = Vector( radius + center.x, center.y, center.z ); - float angle; - for( angle=0.0f; angle <= 360.0f; angle += 22.5f ) - { - edge.x = radius * cosf( angle / 180.0f * M_PI ) + center.x; - edge.y = center.y; - edge.z = radius * sinf( angle / 180.0f * M_PI ) + center.z; - - Line( edge, lastEdge, r, g, b, noDepthTest, flDuration ); - - lastEdge = edge; - } - - lastEdge = Vector( center.x, radius + center.y, center.z ); - for( angle=0.0f; angle <= 360.0f; angle += 22.5f ) - { - edge.x = center.x; - edge.y = radius * cosf( angle / 180.0f * M_PI ) + center.y; - edge.z = radius * sinf( angle / 180.0f * M_PI ) + center.z; - - Line( edge, lastEdge, r, g, b, noDepthTest, flDuration ); - - lastEdge = edge; - } - - lastEdge = Vector( center.x, radius + center.y, center.z ); - for( angle=0.0f; angle <= 360.0f; angle += 22.5f ) - { - edge.x = radius * cosf( angle / 180.0f * M_PI ) + center.x; - edge.y = radius * sinf( angle / 180.0f * M_PI ) + center.y; - edge.z = center.z; - - Line( edge, lastEdge, r, g, b, noDepthTest, flDuration ); - - lastEdge = edge; - } - } - void CircleOriented(const Vector &position, const QAngle &angles, float radius, int r, int g, int b, int a, bool bNoDepthTest, float flDuration) - { - RETURN_IF_CANNOT_DRAW_OVERLAY - - matrix3x4_t xform; - AngleMatrix(angles, position, xform); - Vector xAxis, yAxis; - MatrixGetColumn(xform, 2, xAxis); - MatrixGetColumn(xform, 1, yAxis); - Circle(position, xAxis, yAxis, radius, r, g, b, a, bNoDepthTest, flDuration); - } - void Circle(const Vector &position, const Vector &xAxis, const Vector &yAxis, float radius, int r, int g, int b, int a, bool bNoDepthTest, float flDuration) - { - RETURN_IF_CANNOT_DRAW_OVERLAY - - const unsigned int nSegments = 16; - const float flRadStep = (M_PI*2.0f) / (float) nSegments; - - Vector vecLastPosition; - Vector vecStart = position + xAxis * radius; - Vector vecPosition = vecStart; - - for ( int i = 1; i <= nSegments; i++ ) - { - vecLastPosition = vecPosition; - - float flSin, flCos; - SinCos( flRadStep*i, &flSin, &flCos ); - vecPosition = position + (xAxis * flCos * radius) + (yAxis * flSin * radius); - - Line( vecLastPosition, vecPosition, r, g, b, bNoDepthTest, flDuration ); - - if ( a && i > 1 ) - { - debugoverlay->AddTriangleOverlay( vecStart, vecLastPosition, vecPosition, r, g, b, a, bNoDepthTest, flDuration ); - } - } - } - void SetDebugBits(HSCRIPT hEntity, int bit) // DebugOverlayBits_t - { - CBaseEntity *pEnt = ToEnt(hEntity); - if (!pEnt) - return; - - if (pEnt->m_debugOverlays & bit) - { - pEnt->m_debugOverlays &= ~bit; - } - else - { - pEnt->m_debugOverlays |= bit; - -#ifdef AI_MONITOR_FOR_OSCILLATION - if (pEnt->IsNPC()) - { - pEnt->MyNPCPointer()->m_ScheduleHistory.RemoveAll(); - } -#endif//AI_MONITOR_FOR_OSCILLATION - } - } - void ClearAllOverlays() - { - // Clear all entities of their debug overlays - for (CBaseEntity *pEntity = gEntList.FirstEnt(); pEntity; pEntity = gEntList.NextEnt(pEntity)) - { - pEntity->m_debugOverlays = 0; - } - - if (debugoverlay) - { - debugoverlay->ClearAllOverlays(); - } - } - -private: -} g_ScriptDebugOverlay; - -BEGIN_SCRIPTDESC_ROOT(CDebugOverlayScriptHelper, SCRIPT_SINGLETON "CDebugOverlayScriptHelper") - DEFINE_SCRIPTFUNC( Box, "Draws a world-space axis-aligned box. Specify bounds in world space." ) - DEFINE_SCRIPTFUNC( BoxDirection, "Draw box oriented to a Vector direction" ) - DEFINE_SCRIPTFUNC( BoxAngles, "Draws an oriented box at the origin. Specify bounds in local space." ) - DEFINE_SCRIPTFUNC( SweptBox, "Draws a swept box. Specify endpoints in world space and the bounds in local space." ) - DEFINE_SCRIPTFUNC( EntityBounds, "Draws bounds of an entity" ) - DEFINE_SCRIPTFUNC( Line, "Draws a line between two points" ) - DEFINE_SCRIPTFUNC( Triangle, "Draws a filled triangle. Specify vertices in world space." ) - DEFINE_SCRIPTFUNC( EntityText, "Draws text on an entity" ) - DEFINE_SCRIPTFUNC( EntityTextAtPosition, "Draw entity text overlay at a specific position" ) - DEFINE_SCRIPTFUNC( Grid, "Add grid overlay" ) - DEFINE_SCRIPTFUNC( Text, "Draws 2D text. Specify origin in world space." ) - DEFINE_SCRIPTFUNC( ScreenText, "Draws 2D text. Specify coordinates in screen space." ) - DEFINE_SCRIPTFUNC( Cross3D, "Draws a world-aligned cross. Specify origin in world space." ) - DEFINE_SCRIPTFUNC( Cross3DOriented, "Draws an oriented cross. Specify origin in world space." ) - DEFINE_SCRIPTFUNC( DrawTickMarkedLine, "Draws a dashed line. Specify endpoints in world space." ) - DEFINE_SCRIPTFUNC( HorzArrow, "Draws a horizontal arrow. Specify endpoints in world space." ) - DEFINE_SCRIPTFUNC( YawArrow, "Draws a arrow associated with a specific yaw. Specify endpoints in world space." ) - DEFINE_SCRIPTFUNC( VertArrow, "Draws a vertical arrow. Specify endpoints in world space." ) - DEFINE_SCRIPTFUNC( Axis, "Draws an axis. Specify origin + orientation in world space." ) - DEFINE_SCRIPTFUNC( Sphere, "Draws a wireframe sphere. Specify center in world space." ) - DEFINE_SCRIPTFUNC( CircleOriented, "Draws a circle oriented. Specify center in world space." ) - DEFINE_SCRIPTFUNC( Circle, "Draws a circle. Specify center in world space." ) - DEFINE_SCRIPTFUNC( SetDebugBits, "Set debug bits on entity" ) - DEFINE_SCRIPTFUNC( ClearAllOverlays, "Clear all debug overlays at once" ) -END_SCRIPTDESC(); -#endif // MAPBASE_VSCRIPT - - //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- @@ -1010,9 +566,7 @@ bool VScriptServerInit() } g_pScriptVM->RegisterInstance( &g_ScriptEntityIterator, "Entities" ); -#ifdef MAPBASE_VSCRIPT - g_pScriptVM->RegisterInstance( &g_ScriptDebugOverlay, "debugoverlay" ); -#endif // MAPBASE_VSCRIPT + #ifdef MAPBASE_VSCRIPT g_pScriptVM->RegisterAllClasses(); @@ -1029,6 +583,7 @@ bool VScriptServerInit() g_pScriptVM->Run( g_Script_vscript_server ); } + VScriptRunScript( "vscript_server", true ); VScriptRunScript( "mapspawn", false ); #ifdef MAPBASE_VSCRIPT @@ -1192,6 +747,9 @@ public: virtual void LevelShutdownPostEntity( void ) { +#ifdef MAPBASE_VSCRIPT + g_ScriptNetMsg->LevelShutdownPreVM(); +#endif VScriptServerTerm(); } diff --git a/sp/src/game/server/vscript_server.nut b/sp/src/game/server/vscript_server.nut index 17ba64d3..deecea7b 100644 --- a/sp/src/game/server/vscript_server.nut +++ b/sp/src/game/server/vscript_server.nut @@ -5,13 +5,16 @@ static char g_Script_vscript_server[] = R"vscript( // //============================================================================= -function UniqueString( string = "" ) -{ - return ::DoUniqueString( string.tostring() ); -} - local DoEntFire = ::DoEntFire local DoEntFireByInstanceHandle = ::DoEntFireByInstanceHandle +local DoDispatchParticleEffect = ::DoDispatchParticleEffect +local DoUniqueString = ::DoUniqueString +local ScriptGetClientConvarValue = ::ScriptGetClientConvarValue + +function UniqueString( string = "" ) +{ + return DoUniqueString( string.tostring() ); +} function EntFire( target, action, value = null, delay = 0.0, activator = null, caller = null ) { @@ -67,10 +70,10 @@ function DispatchParticleEffect( particleName, origin, angles, entity = null ) // CConvars is declared within the library function CConvars::GetClientConvarValue(cvar,idx) { - return ::ScriptGetClientConvarValue(cvar,idx); + return ScriptGetClientConvarValue(cvar,idx); } -RegisterHelp( "CConvars::GetClientConvarValue", "CConvars::GetClientConvarValue(string, int)", "Returns the convar value for the entindex as a string. Only works with client convars with the FCVAR_USERINFO flag." ); +__Documentation.RegisterHelp( "CConvars::GetClientConvarValue", "CConvars::GetClientConvarValue(string, int)", "Returns the convar value for the entindex as a string. Only works with client convars with the FCVAR_USERINFO flag." ); function __ReplaceClosures( script, scope ) { diff --git a/sp/src/game/shared/hl2/hl2_usermessages.cpp b/sp/src/game/shared/hl2/hl2_usermessages.cpp index 0ab97330..870af835 100644 --- a/sp/src/game/shared/hl2/hl2_usermessages.cpp +++ b/sp/src/game/shared/hl2/hl2_usermessages.cpp @@ -55,4 +55,8 @@ void RegisterUserMessages( void ) // NVNT register haptic user messages RegisterHapticMessages(); #endif + +#ifdef MAPBASE_VSCRIPT + usermessages->Register( "ScriptMsg", -1 ); // CNetMsgScriptHelper +#endif } \ No newline at end of file diff --git a/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp b/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp index c0668e8f..ae927a81 100644 --- a/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp +++ b/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp @@ -852,10 +852,4 @@ void RegisterSharedScriptFunctions() ScriptRegisterFunctionNamed( g_pScriptVM, ScriptIsClient, "IsClient", "Returns true if the script is being run on the client." ); RegisterScriptSingletons(); - -#ifdef CLIENT_DLL - VScriptRunScript( "vscript_client", true ); -#else - VScriptRunScript( "vscript_server", true ); -#endif } diff --git a/sp/src/game/shared/mapbase/vscript_singletons.cpp b/sp/src/game/shared/mapbase/vscript_singletons.cpp index 0f7fcec4..ced83297 100644 --- a/sp/src/game/shared/mapbase/vscript_singletons.cpp +++ b/sp/src/game/shared/mapbase/vscript_singletons.cpp @@ -12,14 +12,16 @@ #include #include #include "ammodef.h" +#include "tier1/utlcommon.h" #ifndef CLIENT_DLL -#include "usermessages.h" #include "ai_squad.h" #endif // !CLIENT_DLL +#include "usermessages.h" #include "filesystem.h" #include "igameevents.h" +#include "engine/ivdebugoverlay.h" #include "vscript_singletons.h" @@ -27,6 +29,7 @@ #include "tier0/memdbgon.h" extern IScriptManager *scriptmanager; +CNetMsgScriptHelper *g_ScriptNetMsg = new CNetMsgScriptHelper(); //============================================================================= // Net Prop Manager @@ -374,12 +377,11 @@ public: private: bool m_bActive; - const char *m_pszContext; + unsigned int m_iContextHash; HSCRIPT m_hCallback; - static const char *FindContext( const char *szContext, CScriptGameEventListener *pIgnore = NULL ); - //inline const char *GetContext( CScriptGameEventListener *p ); - //inline const char *GetContext(); + static StringHashFunctor Hash; + static inline unsigned int HashContext( const char* c ) { return (c && *c) ? Hash(c) : 0; } public: static void DumpEventListeners(); @@ -389,20 +391,22 @@ public: static void WriteEventData( IGameEvent *event, HSCRIPT hTable ); #endif // !CLIENT_DLL -private: +public: #ifndef CLIENT_DLL - static CUtlVector< KeyValues* > s_GameEvents; -#endif // !CLIENT_DLL + static CUtlMap< unsigned int, KeyValues* > s_GameEvents; +#endif static CUtlVectorAutoPurge< CScriptGameEventListener* > s_GameEventListeners; - + static CUtlVector< KeyValues* > s_LoadedFiles; }; #ifndef CLIENT_DLL -CUtlVector< KeyValues* > CScriptGameEventListener::s_GameEvents; -#endif // !CLIENT_DLL +CUtlMap< unsigned int, KeyValues* > CScriptGameEventListener::s_GameEvents( DefLessFunc(unsigned int) ); +#endif CUtlVectorAutoPurge< CScriptGameEventListener* > CScriptGameEventListener::s_GameEventListeners; +CUtlVector< KeyValues* > CScriptGameEventListener::s_LoadedFiles; +StringHashFunctor CScriptGameEventListener::Hash; -#if 0 +#if _DEBUG #ifdef CLIENT_DLL CON_COMMAND_F( cl_dump_script_game_event_listeners, "Dump all game event listeners created from script.", FCVAR_CHEAT ) { @@ -424,9 +428,9 @@ void CScriptGameEventListener::DumpEventListeners() CGMsg( 0, CON_GROUP_VSCRIPT, "--- Script game event listener dump start\n" ); FOR_EACH_VEC( s_GameEventListeners, i ) { - CGMsg( 0, CON_GROUP_VSCRIPT, " %d (0x%p) %d : %s\n", i,s_GameEventListeners[i], + CGMsg( 0, CON_GROUP_VSCRIPT, " %d (0x%p) %d : %d\n", i,s_GameEventListeners[i], s_GameEventListeners[i], - s_GameEventListeners[i]->m_pszContext ? s_GameEventListeners[i]->m_pszContext : ""); + s_GameEventListeners[i]->m_iContextHash ); } CGMsg( 0, CON_GROUP_VSCRIPT, "--- Script game event listener dump end\n" ); } @@ -473,10 +477,11 @@ void CScriptGameEventListener::LoadAllEvents() }; // Destroy old KeyValues - if ( s_GameEvents.Count() ) + if ( s_LoadedFiles.Count() ) { - for ( int i = 0; i < s_GameEvents.Count(); ++i ) - s_GameEvents[i]->deleteThis(); + for ( int i = s_LoadedFiles.Count(); i--; ) + s_LoadedFiles[i]->deleteThis(); + s_LoadedFiles.Purge(); s_GameEvents.Purge(); } @@ -496,7 +501,7 @@ void CScriptGameEventListener::LoadEventsFromFile( const char *filename, const c if ( !pKV->LoadFromFile( filesystem, filename, pathID ) ) { - // CGMsg( 1, CON_GROUP_VSCRIPT, "CScriptGameEventListener::LoadEventsFromFile: Failed to load file %s, %s\n", filename, pathID ); + // CGMsg( 1, CON_GROUP_VSCRIPT, "CScriptGameEventListener::LoadEventsFromFile: Failed to load file [%s]%s\n", pathID, filename ); pKV->deleteThis(); return; } @@ -504,6 +509,7 @@ void CScriptGameEventListener::LoadEventsFromFile( const char *filename, const c // Set the key value types to what they are from their string description values to read the correct data type in WriteEventData. // There might be a better way of doing this, but this is okay since it's only done on file load. for ( KeyValues *key = pKV->GetFirstSubKey(); key; key = key->GetNextKey() ) + { for ( KeyValues *sub = key->GetFirstSubKey(); sub; sub = sub->GetNextKey() ) { if ( sub->GetDataType() == KeyValues::TYPE_STRING ) @@ -527,9 +533,16 @@ void CScriptGameEventListener::LoadEventsFromFile( const char *filename, const c // float : float, 32 bit } - CGMsg( 2, CON_GROUP_VSCRIPT, "CScriptGameEventListener::LoadEventsFromFile: Loaded %s, %s\n", filename, pathID ); + // Store event subkeys + // Replace key so modevents can overwrite gameevents. + // It does not check for hash collisions, however. + s_GameEvents.InsertOrReplace( Hash( key->GetName() ), key ); + } - s_GameEvents.AddToTail(pKV); + // Store files (allocated KV) + s_LoadedFiles.AddToTail( pKV ); + + CGMsg( 2, CON_GROUP_VSCRIPT, "CScriptGameEventListener::LoadEventsFromFile: Loaded [%s]%s\n", pathID, filename ); } //----------------------------------------------------------------------------- @@ -537,94 +550,55 @@ void CScriptGameEventListener::LoadEventsFromFile( const char *filename, const c //----------------------------------------------------------------------------- void CScriptGameEventListener::WriteEventData( IGameEvent *event, HSCRIPT hTable ) { - // TODO: Something more efficient than iterating through all the events that ever exist one by one - - const char *szEvent = event->GetName(); - for ( int i = 0; i < s_GameEvents.Count(); ++i ) + int i = s_GameEvents.Find( Hash( event->GetName() ) ); + if ( i != s_GameEvents.InvalidIndex() ) { KeyValues *pKV = s_GameEvents[i]; - for ( KeyValues *key = pKV->GetFirstSubKey(); key; key = key->GetNextKey() ) + for ( KeyValues *sub = pKV->GetFirstSubKey(); sub; sub = sub->GetNextKey() ) { - if ( !V_stricmp( key->GetName(), szEvent ) ) + const char *szKey = sub->GetName(); + switch ( sub->GetDataType() ) { - for ( KeyValues *sub = key->GetFirstSubKey(); sub; sub = sub->GetNextKey() ) - { - const char *szKey = sub->GetName(); - switch ( sub->GetDataType() ) - { - case KeyValues::TYPE_STRING: g_pScriptVM->SetValue( hTable, szKey, event->GetString( szKey ) ); break; - case KeyValues::TYPE_INT: g_pScriptVM->SetValue( hTable, szKey, event->GetInt ( szKey ) ); break; - case KeyValues::TYPE_FLOAT: g_pScriptVM->SetValue( hTable, szKey, event->GetFloat ( szKey ) ); break; - // default: DevWarning( 2, "CScriptGameEventListener::WriteEventData: unknown data type '%d' on key '%s' in event '%s'\n", sub->GetDataType(), szKey, szEvent ); - } - } - return; + case KeyValues::TYPE_STRING: g_pScriptVM->SetValue( hTable, szKey, event->GetString( szKey ) ); break; + case KeyValues::TYPE_INT: g_pScriptVM->SetValue( hTable, szKey, event->GetInt ( szKey ) ); break; + case KeyValues::TYPE_FLOAT: g_pScriptVM->SetValue( hTable, szKey, event->GetFloat ( szKey ) ); break; + // default: DevWarning( 2, "CScriptGameEventListener::WriteEventData: unknown data type '%d' on key '%s' in event '%s'\n", sub->GetDataType(), szKey, szEvent ); } } } } #endif // !CLIENT_DLL -//----------------------------------------------------------------------------- -// Find if context is in use by others; used to alloc/dealloc only when required. -// Returns allocated pointer to string -// Expects non-NULL context input -//----------------------------------------------------------------------------- -const char *CScriptGameEventListener::FindContext( const char *szContext, CScriptGameEventListener *pIgnore ) -{ - for ( int i = s_GameEventListeners.Count(); i--; ) - { - CScriptGameEventListener *pCur = s_GameEventListeners[i]; - if ( pCur != pIgnore ) - { - if ( pCur->m_pszContext && !V_stricmp( szContext, pCur->m_pszContext ) ) - { - return pCur->m_pszContext; - } - } - } - return NULL; -} //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- intptr_t CScriptGameEventListener::ListenToGameEvent( const char* szEvent, HSCRIPT hFunc, const char* szContext ) { - m_bActive = true; + bool bValid; - char *psz; + if ( gameeventmanager && hFunc ) +#ifdef CLIENT_DLL + bValid = gameeventmanager->AddListener( this, szEvent, false ); +#else + bValid = gameeventmanager->AddListener( this, szEvent, true ); +#endif + else bValid = false; - if ( szContext && *szContext ) + if ( bValid ) { - psz = const_cast(FindContext(szContext)); - if ( !psz ) - { - int len = V_strlen(szContext) + 1; - if ( len > 1 ) - { - int size = min( len, 256 ); // arbitrary clamp - psz = new char[size]; - V_strncpy( psz, szContext, size ); - } - } + m_iContextHash = HashContext( szContext ); + m_hCallback = hFunc; + m_bActive = true; + + s_GameEventListeners.AddToTail( this ); + + return reinterpret_cast( this ); // POINTER_TO_INT } else { - psz = NULL; + delete this; + return 0x0; } - - m_pszContext = psz; - m_hCallback = hFunc; - - if ( gameeventmanager ) -#ifdef CLIENT_DLL - gameeventmanager->AddListener( this, szEvent, false ); -#else - gameeventmanager->AddListener( this, szEvent, true ); -#endif - s_GameEventListeners.AddToTail( this ); - - return reinterpret_cast(this); // POINTER_TO_INT } //----------------------------------------------------------------------------- @@ -639,27 +613,16 @@ void CScriptGameEventListener::StopListeningForEvent() { g_pScriptVM->ReleaseScript( m_hCallback ); } - else if ( m_hCallback ) + else { - AssertMsg( 0, "LEAK (0x%p)\n", (void*)m_hCallback ); - } - - if ( m_pszContext ) - { - if ( !FindContext( m_pszContext, this ) ) - { - delete[] m_pszContext; - } - - m_pszContext = NULL; + // AssertMsg( !m_hCallback, "LEAK (0x%p)\n", (void*)m_hCallback ); } m_hCallback = NULL; + m_bActive = false; if ( gameeventmanager ) gameeventmanager->RemoveListener( this ); - - m_bActive = false; } //----------------------------------------------------------------------------- @@ -683,42 +646,18 @@ bool CScriptGameEventListener::StopListeningToGameEvent( intptr_t listener ) //----------------------------------------------------------------------------- void CScriptGameEventListener::StopListeningToAllGameEvents( const char* szContext ) { - if ( szContext ) + unsigned int hash = HashContext( szContext ); + + // Iterate from the end so they can be safely removed as they are deleted + for ( int i = s_GameEventListeners.Count(); i--; ) { - if ( *szContext ) + CScriptGameEventListener *pCur = s_GameEventListeners[i]; + if ( pCur->m_iContextHash == hash ) { - // Iterate from the end so they can be safely removed as they are deleted - for ( int i = s_GameEventListeners.Count(); i--; ) - { - CScriptGameEventListener *pCur = s_GameEventListeners[i]; - if ( pCur->m_pszContext && !V_stricmp( szContext, pCur->m_pszContext ) ) - { - s_GameEventListeners.Remove(i); // keep list order - delete pCur; - } - } - } - else // empty (NULL) context - { - for ( int i = s_GameEventListeners.Count(); i--; ) - { - CScriptGameEventListener *pCur = s_GameEventListeners[i]; - if ( !pCur->m_pszContext ) - { - s_GameEventListeners.Remove(i); - delete pCur; - } - } + s_GameEventListeners.Remove(i); // keep list order + delete pCur; } } -#if 0 - if ( !szContext ) - { - for ( int i = s_GameEventListeners.Count(); i--; ) - delete s_GameEventListeners[i]; - s_GameEventListeners.Purge(); - } -#endif } //============================================================================= @@ -794,7 +733,7 @@ static void FireGameEventLocal( const char* szEvent, HSCRIPT hTable ) //============================================================================= // Save/Restore Utility -// Based on Source 2 API +// Based on L4D2 API //============================================================================= class CScriptSaveRestoreUtil : public CAutoGameSystem { @@ -803,8 +742,8 @@ public: static void RestoreTable( const char *szId, HSCRIPT hTable ); static void ClearSavedTable( const char *szId ); -// IGameSystem interface -public: +public: // IGameSystem + void OnSave() { if ( g_pScriptVM ) @@ -813,6 +752,7 @@ public: if ( hFunc ) { g_pScriptVM->Call( hFunc ); + g_pScriptVM->ReleaseScript( hFunc ); } } } @@ -825,72 +765,43 @@ public: if ( hFunc ) { g_pScriptVM->Call( hFunc ); + g_pScriptVM->ReleaseScript( hFunc ); } } } void Shutdown() { - FOR_EACH_VEC( m_aKeyValues, i ) - m_aKeyValues[i]->deleteThis(); - m_aKeyValues.Purge(); - m_aContext.PurgeAndDeleteElements(); + FOR_EACH_MAP_FAST( m_Lookup, i ) + m_Lookup[i]->deleteThis(); + m_Lookup.Purge(); } private: - static int GetIndexForContext( const char *szId ); - - // indices must match, always remove keeping order - static CUtlStringList m_aContext; - static CUtlVector m_aKeyValues; + static StringHashFunctor Hash; + static CUtlMap< unsigned int, KeyValues* > m_Lookup; } g_ScriptSaveRestoreUtil; -CUtlStringList CScriptSaveRestoreUtil::m_aContext; -CUtlVector CScriptSaveRestoreUtil::m_aKeyValues; - -int CScriptSaveRestoreUtil::GetIndexForContext( const char *szId ) -{ - int idx = -1; - FOR_EACH_VEC( m_aContext, i ) - { - if ( !V_stricmp( szId, m_aContext[i] ) ) - { - idx = i; - break; - } - } - return idx; -} +CUtlMap< unsigned int, KeyValues* > CScriptSaveRestoreUtil::m_Lookup( DefLessFunc(unsigned int) ); +StringHashFunctor CScriptSaveRestoreUtil::Hash; //----------------------------------------------------------------------------- // Store a table with primitive values that will persist across level transitions and save loads. +// Case sensitive //----------------------------------------------------------------------------- void CScriptSaveRestoreUtil::SaveTable( const char *szId, HSCRIPT hTable ) { - int idx = GetIndexForContext(szId); - KeyValues *pKV; - - if ( idx == -1 ) + int idx = m_Lookup.Find( Hash(szId) ); + if ( idx == m_Lookup.InvalidIndex() ) { pKV = new KeyValues("ScriptSavedTable"); - m_aKeyValues.AddToTail(pKV); - - if ( V_strlen(szId) > 255 ) // arbitrary clamp - { - char c[256]; - V_strncpy( c, szId, sizeof(c) ); - m_aContext.CopyAndAddToTail(c); - } - else - { - m_aContext.CopyAndAddToTail(szId); - } + m_Lookup.Insert( Hash(szId), pKV ); } else { - pKV = m_aKeyValues[idx]; + pKV = m_Lookup[idx]; pKV->Clear(); } @@ -916,20 +827,14 @@ void CScriptSaveRestoreUtil::SaveTable( const char *szId, HSCRIPT hTable ) //----------------------------------------------------------------------------- void CScriptSaveRestoreUtil::RestoreTable( const char *szId, HSCRIPT hTable ) { - int idx = GetIndexForContext(szId); - - KeyValues *pKV; - - if ( idx == -1 ) + int idx = m_Lookup.Find( Hash(szId) ); + if ( idx == m_Lookup.InvalidIndex() ) { // DevWarning( 2, "RestoreTable could not find saved table with context '%s'\n", szId ); return; } - else - { - pKV = m_aKeyValues[idx]; - } + KeyValues *pKV = m_Lookup[idx]; FOR_EACH_SUBKEY( pKV, key ) { switch ( key->GetDataType() ) @@ -946,19 +851,16 @@ void CScriptSaveRestoreUtil::RestoreTable( const char *szId, HSCRIPT hTable ) //----------------------------------------------------------------------------- void CScriptSaveRestoreUtil::ClearSavedTable( const char *szId ) { - int idx = GetIndexForContext(szId); - - if ( idx == -1 ) + int idx = m_Lookup.Find( Hash(szId) ); + if ( idx != m_Lookup.InvalidIndex() ) + { + m_Lookup[idx]->deleteThis(); + m_Lookup.RemoveAt( idx ); + } + else { // DevWarning( 2, "ClearSavedTable could not find saved table with context '%s'\n", szId ); - return; } - - m_aKeyValues[idx]->deleteThis(); - m_aKeyValues.Remove(idx); - - delete[] m_aContext[idx]; - m_aContext.Remove(idx); } //============================================================================= @@ -972,14 +874,15 @@ void CScriptSaveRestoreUtil::ClearSavedTable( const char *szId ) class CScriptReadWriteFile : public CAutoGameSystem { + // A singleton class with all static members is used to be able to free the read string on level shutdown, + // and register script funcs directly. Same reason applies to CScriptSaveRestoreUtil public: - static bool ScriptFileWrite( const char *szFile, const char *szInput ); - static const char *ScriptFileRead( const char *szFile ); - //static const char *CRC32_Checksum( const char *szFilename ); + static bool FileWrite( const char *szFile, const char *szInput ); + static const char *FileRead( const char *szFile ); // NOTE: These two functions are new with Mapbase and have no Valve equivalent - static bool ScriptKeyValuesWrite( const char *szFile, HSCRIPT hInput ); - static HSCRIPT ScriptKeyValuesRead( const char *szFile ); + static bool KeyValuesWrite( const char *szFile, HSCRIPT hInput ); + static HSCRIPT KeyValuesRead( const char *szFile ); void LevelShutdownPostEntity() { @@ -988,27 +891,19 @@ public: delete[] m_pszReturnReadFile; m_pszReturnReadFile = NULL; } - - //if ( m_pszReturnCRC32 ) - //{ - // delete[] m_pszReturnCRC32; - // m_pszReturnCRC32 = NULL; - //} } private: static const char *m_pszReturnReadFile; - //static const char *m_pszReturnCRC32; } g_ScriptReadWrite; const char *CScriptReadWriteFile::m_pszReturnReadFile = NULL; -//const char *CScriptReadWriteFile::m_pszReturnCRC32 = NULL; //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- -bool CScriptReadWriteFile::ScriptFileWrite( const char *szFile, const char *szInput ) +bool CScriptReadWriteFile::FileWrite( const char *szFile, const char *szInput ) { size_t len = strlen(szInput); if ( len > SCRIPT_MAX_FILE_WRITE_SIZE ) @@ -1043,7 +938,7 @@ bool CScriptReadWriteFile::ScriptFileWrite( const char *szFile, const char *szIn //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- -const char *CScriptReadWriteFile::ScriptFileRead( const char *szFile ) +const char *CScriptReadWriteFile::FileRead( const char *szFile ) { char pszFullName[MAX_PATH]; V_snprintf( pszFullName, sizeof(pszFullName), SCRIPT_RW_FULL_PATH_FMT, szFile ); @@ -1101,7 +996,7 @@ const char *CScriptReadWriteFile::CRC32_Checksum( const char *szFilename ) //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- -bool CScriptReadWriteFile::ScriptKeyValuesWrite( const char *szFile, HSCRIPT hInput ) +bool CScriptReadWriteFile::KeyValuesWrite( const char *szFile, HSCRIPT hInput ) { KeyValues *pKV = scriptmanager->GetKeyValuesFromScriptKV( g_pScriptVM, hInput ); if (!pKV) @@ -1114,7 +1009,7 @@ bool CScriptReadWriteFile::ScriptKeyValuesWrite( const char *szFile, HSCRIPT hIn if ( buf.Size() > SCRIPT_MAX_FILE_WRITE_SIZE ) { - DevWarning( 2, "Input is too large for a ScriptFileWrite ( %s / %d MB )\n", V_pretifymem(buf.Size(),2,true), (SCRIPT_MAX_FILE_WRITE_SIZE >> 20) ); + DevWarning( 2, "Input is too large for a ScriptKeyValuesWrite ( %s / %d MB )\n", V_pretifymem(buf.Size(),2,true), (SCRIPT_MAX_FILE_WRITE_SIZE >> 20) ); buf.Purge(); return false; } @@ -1143,7 +1038,7 @@ bool CScriptReadWriteFile::ScriptKeyValuesWrite( const char *szFile, HSCRIPT hIn //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- -HSCRIPT CScriptReadWriteFile::ScriptKeyValuesRead( const char *szFile ) +HSCRIPT CScriptReadWriteFile::KeyValuesRead( const char *szFile ) { char pszFullName[MAX_PATH]; V_snprintf( pszFullName, sizeof(pszFullName), SCRIPT_RW_FULL_PATH_FMT, szFile ); @@ -1157,7 +1052,7 @@ HSCRIPT CScriptReadWriteFile::ScriptKeyValuesRead( const char *szFile ) unsigned int size = g_pFullFileSystem->Size( pszFullName, SCRIPT_RW_PATH_ID ); if ( size >= SCRIPT_MAX_FILE_READ_SIZE ) { - DevWarning( 2, "File '%s' (from '%s') is too large for a ScriptFileRead ( %s / %u bytes )\n", pszFullName, szFile, V_pretifymem(size,2,true), SCRIPT_MAX_FILE_READ_SIZE ); + DevWarning( 2, "File '%s' (from '%s') is too large for a ScriptKeyValuesRead ( %s / %u bytes )\n", pszFullName, szFile, V_pretifymem(size,2,true), SCRIPT_MAX_FILE_READ_SIZE ); return NULL; } @@ -1178,156 +1073,977 @@ HSCRIPT CScriptReadWriteFile::ScriptKeyValuesRead( const char *szFile ) #undef SCRIPT_RW_FULL_PATH_FMT //============================================================================= -// User Message Helper -// Based on Source 2 API +// Network message helper +// (Unique to mapbase) +// +// Uses usermessages for server to client, UserCmd for client to server communication. +// The custom message name is hashed and sent as word with the message. //============================================================================= -#ifndef CLIENT_DLL -class CNetMsgScriptHelper + + +#ifdef GAME_DLL +#define m_MsgIn_() m_MsgIn-> +#else +#define m_MsgIn_() m_MsgIn. +#endif + + +void CNetMsgScriptHelper::WriteToBuffer( bf_write *bf ) { -private: - CRecipientFilter filter; - bf_write message; - byte data_msg[ MAX_USER_MSG_DATA ]; + bf->WriteBits( m_MsgOut.GetData(), m_MsgOut.GetNumBitsWritten() ); +} - inline void SendMsg( bf_write *bf ) +//----------------------------------------------------------------------------- +// Reset the current network message buffer +//----------------------------------------------------------------------------- +void CNetMsgScriptHelper::Reset() +{ + m_MsgOut.StartWriting( m_MsgData, sizeof(m_MsgData), 0 ); +#ifdef GAME_DLL + m_filter.Reset(); +#else + m_MsgIn_()Reset(); + m_bWriteReady = false; +#endif +} + +//----------------------------------------------------------------------------- +// Create the storage for the reciever callback functions. +// Functions are handled in the VM, the storage table is here. +//----------------------------------------------------------------------------- +void CNetMsgScriptHelper::InitPostVM() +{ + ScriptVariant_t hHooks; + g_pScriptVM->CreateTable( hHooks ); +#if _DEBUG + g_pScriptVM->SetValue( NULL, "__NetMsg_hooks", hHooks ); +#endif + m_Hooks = (HSCRIPT)hHooks; +} + +void CNetMsgScriptHelper::LevelShutdownPreVM() +{ + Reset(); + if ( m_Hooks ) { - bf_read buffer = bf_read(); - buffer.StartReading( message.GetData(), message.m_nDataBytes ); - bf->WriteBitsFromBuffer( &buffer, message.GetNumBitsWritten() ); - engine->MessageEnd(); + g_pScriptVM->ReleaseScript( m_Hooks ); } + m_Hooks = NULL; +} -public: - inline void Reset() - { - message.StartWriting( data_msg, sizeof(data_msg) ); - filter.Reset(); - } +#ifdef CLIENT_DLL - void SendUserMessage( HSCRIPT player, const char *msg, bool bReliable ) +bool CNetMsgScriptHelper::Init() // IGameSystem +{ + usermessages->HookMessage( "ScriptMsg", __MsgFunc_ScriptMsg ); + return true; +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CNetMsgScriptHelper::__MsgFunc_ScriptMsg( bf_read &msg ) +{ + g_ScriptNetMsg->RecieveMessage( msg ); +} + +#endif // CLIENT_DLL + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +#ifdef GAME_DLL +void CNetMsgScriptHelper::RecieveMessage( bf_read *msg, CBaseEntity *pPlayer ) +{ + m_MsgIn = msg; +#else +void CNetMsgScriptHelper::RecieveMessage( bf_read &msg ) +{ + m_MsgIn.StartReading( msg.m_pData, msg.m_nDataBytes ); +#endif + + word hash = m_MsgIn_()ReadWord(); + + ScriptVariant_t hfn; + if ( g_pScriptVM->GetValue( m_Hooks, hash, &hfn ) ) { - int msg_type = usermessages->LookupUserMessage(msg); - if ( msg_type == -1 ) +#ifdef GAME_DLL + if ( g_pScriptVM->Call( hfn, NULL, true, NULL, pPlayer->m_hScriptInstance ) == SCRIPT_ERROR ) +#else + if ( g_pScriptVM->ExecuteFunction( hfn, NULL, 0, NULL, NULL, true ) == SCRIPT_ERROR ) +#endif { - g_pScriptVM->RaiseException("UserMessageBegin: Unregistered message"); + DevWarning( 3, "NetMsg: invalid callback for '%d'\n", hash ); + } + g_pScriptVM->ReleaseValue( hfn ); + } + else + { + DevWarning( 3, "NetMsg hook not found for '%d'\n", hash ); + } +} + +//----------------------------------------------------------------------------- +// Start writing new custom network message +//----------------------------------------------------------------------------- +void CNetMsgScriptHelper::Start( const char *msg ) +{ + Reset(); + m_MsgOut.WriteWord( HashStringCaseless(msg) ); +} + +//----------------------------------------------------------------------------- +// server -> client +// +// Sends an exclusive usermessage. +//----------------------------------------------------------------------------- +#ifdef GAME_DLL +void CNetMsgScriptHelper::Send( HSCRIPT player, bool bReliable ) +{ + CBaseEntity *pPlayer = ToEnt(player); + if ( pPlayer ) + { + m_filter.AddRecipient( (CBasePlayer*)pPlayer ); + } + + if ( bReliable ) + { + m_filter.MakeReliable(); + } + + DoSendUserMsg( &m_filter, usermessages->LookupUserMessage( "ScriptMsg" ) ); +} +#else // CLIENT_DLL +//----------------------------------------------------------------------------- +// client -> server +// +// Mark UserCmd delta ready. +//----------------------------------------------------------------------------- +void CNetMsgScriptHelper::Send() +{ + m_bWriteReady = true; +} +#endif + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CNetMsgScriptHelper::Recieve( const char *msg, HSCRIPT func ) +{ + if ( func ) + g_pScriptVM->SetValue( m_Hooks, int( HashStringCaseless(msg) ), func ); + else + g_pScriptVM->ClearValue( m_Hooks, int( HashStringCaseless(msg) ) ); +} + +#ifdef GAME_DLL +void CNetMsgScriptHelper::DoSendUserMsg( CRecipientFilter *filter, int type ) +{ + WriteToBuffer( engine->UserMessageBegin( filter, type ) ); + engine->MessageEnd(); +} + +void CNetMsgScriptHelper::DoSendEntityMsg( CBaseEntity *entity, bool reliable ) +{ + WriteToBuffer( engine->EntityMessageBegin( entity->entindex(), entity->GetServerClass(), reliable ) ); + engine->MessageEnd(); +} + +//----------------------------------------------------------------------------- +// Send a usermessage from the server to the client +//----------------------------------------------------------------------------- +void CNetMsgScriptHelper::SendUserMessage( HSCRIPT hPlayer, const char *msg, bool bReliable ) +{ + int msg_type = usermessages->LookupUserMessage(msg); + if ( msg_type == -1 ) + { + g_pScriptVM->RaiseException( UTIL_VarArgs("SendUserMessage: Unregistered message '%s'", msg) ); + return; + } + + CBaseEntity *pPlayer = ToEnt(hPlayer); + if ( pPlayer ) + { + m_filter.AddRecipient( (CBasePlayer*)pPlayer ); + } + + if ( bReliable ) + { + m_filter.MakeReliable(); + } + + DoSendUserMsg( &m_filter, msg_type ); +} + +//----------------------------------------------------------------------------- +// Send a message from a server side entity to its client side counterpart +//----------------------------------------------------------------------------- +void CNetMsgScriptHelper::SendEntityMessage( HSCRIPT hEnt, bool bReliable ) +{ + CBaseEntity *entity = ToEnt(hEnt); + if ( !entity ) + { + g_pScriptVM->RaiseException("SendEntityMessage: invalid entity"); + return; + } + + DoSendEntityMsg( entity, bReliable ); +} +#else +//----------------------------------------------------------------------------- +// Dispatch a usermessage on client +//----------------------------------------------------------------------------- +void CNetMsgScriptHelper::DispatchUserMessage( const char *msg ) +{ + bf_read buffer( m_MsgOut.GetData(), m_MsgOut.GetNumBytesWritten() ); + usermessages->DispatchUserMessage( usermessages->LookupUserMessage(msg), buffer ); +} +#endif // GAME_DLL + +#ifdef GAME_DLL +void CNetMsgScriptHelper::AddRecipient( HSCRIPT player ) +{ + CBaseEntity *pPlayer = ToEnt(player); + if ( pPlayer ) + { + m_filter.AddRecipient( (CBasePlayer*)pPlayer ); + } +} + +void CNetMsgScriptHelper::AddRecipientsByPVS( const Vector &pos ) +{ + m_filter.AddRecipientsByPVS(pos); +} + +void CNetMsgScriptHelper::AddRecipientsByPAS( const Vector &pos ) +{ + m_filter.AddRecipientsByPAS(pos); +} + +void CNetMsgScriptHelper::AddAllPlayers() +{ + m_filter.AddAllPlayers(); +} +#endif // GAME_DLL + +void CNetMsgScriptHelper::WriteInt( int iValue, int bits ) +{ + m_MsgOut.WriteSBitLong( iValue, bits ); +} + +void CNetMsgScriptHelper::WriteUInt( int iValue, int bits ) +{ + m_MsgOut.WriteUBitLong( iValue, bits ); +} + +void CNetMsgScriptHelper::WriteByte( int iValue ) +{ + m_MsgOut.WriteByte( iValue ); +} + +void CNetMsgScriptHelper::WriteChar( int iValue ) +{ + m_MsgOut.WriteChar( iValue ); +} + +void CNetMsgScriptHelper::WriteShort( int iValue ) +{ + m_MsgOut.WriteShort( iValue ); +} + +void CNetMsgScriptHelper::WriteWord( int iValue ) +{ + m_MsgOut.WriteWord( iValue ); +} + +void CNetMsgScriptHelper::WriteLong( int iValue ) +{ + m_MsgOut.WriteLong( iValue ); +} + +void CNetMsgScriptHelper::WriteFloat( float flValue ) +{ + m_MsgOut.WriteFloat( flValue ); +} + +void CNetMsgScriptHelper::WriteNormal( float flValue ) +{ + m_MsgOut.WriteBitNormal( flValue ); +} + +void CNetMsgScriptHelper::WriteAngle( float flValue ) +{ + m_MsgOut.WriteBitAngle( flValue, 8 ); +} + +void CNetMsgScriptHelper::WriteCoord( float flValue ) +{ + m_MsgOut.WriteBitCoord( flValue ); +} + +void CNetMsgScriptHelper::WriteVec3Coord( const Vector& rgflValue ) +{ + m_MsgOut.WriteBitVec3Coord( rgflValue ); +} + +void CNetMsgScriptHelper::WriteVec3Normal( const Vector& rgflValue ) +{ + m_MsgOut.WriteBitVec3Normal( rgflValue ); +} + +void CNetMsgScriptHelper::WriteAngles( const QAngle& rgflValue ) +{ + m_MsgOut.WriteBitAngles( rgflValue ); +} + +void CNetMsgScriptHelper::WriteString( const char *sz ) +{ + m_MsgOut.WriteString( sz ); +} + +void CNetMsgScriptHelper::WriteBool( bool bValue ) +{ + m_MsgOut.WriteOneBit( bValue ? 1 : 0 ); +} + +void CNetMsgScriptHelper::WriteEntity( HSCRIPT hEnt ) +{ + CBaseEntity *p = ToEnt(hEnt); + int i; + if (p) i = p->entindex(); + else i = -1; + m_MsgOut.WriteSBitLong( i, MAX_EDICT_BITS ); +} + +void CNetMsgScriptHelper::WriteEHandle( HSCRIPT hEnt ) +{ + CBaseEntity *pEnt = ToEnt( hEnt ); + long iEncodedEHandle; + if ( pEnt ) + { + EHANDLE hEnt = pEnt; + int iSerialNum = hEnt.GetSerialNumber() & (1 << NUM_NETWORKED_EHANDLE_SERIAL_NUMBER_BITS) - 1; + iEncodedEHandle = hEnt.GetEntryIndex() | (iSerialNum << MAX_EDICT_BITS); + } + else + { + iEncodedEHandle = INVALID_NETWORKED_EHANDLE_VALUE; + } + m_MsgOut.WriteLong( iEncodedEHandle ); +} + +int CNetMsgScriptHelper::ReadInt( int bits ) +{ + return m_MsgIn_()ReadSBitLong(bits); +} + +int CNetMsgScriptHelper::ReadUInt( int bits ) +{ + return m_MsgIn_()ReadUBitLong(bits); +} + +int CNetMsgScriptHelper::ReadByte() +{ + return m_MsgIn_()ReadByte(); +} + +int CNetMsgScriptHelper::ReadChar() +{ + return m_MsgIn_()ReadChar(); +} + +int CNetMsgScriptHelper::ReadShort() +{ + return m_MsgIn_()ReadShort(); +} + +int CNetMsgScriptHelper::ReadWord() +{ + return m_MsgIn_()ReadWord(); +} + +int CNetMsgScriptHelper::ReadLong() +{ + return m_MsgIn_()ReadLong(); +} + +float CNetMsgScriptHelper::ReadFloat() +{ + return m_MsgIn_()ReadFloat(); +} + +float CNetMsgScriptHelper::ReadNormal() +{ + return m_MsgIn_()ReadBitNormal(); +} + +float CNetMsgScriptHelper::ReadAngle() +{ + return m_MsgIn_()ReadBitAngle( 8 ); +} + +float CNetMsgScriptHelper::ReadCoord() +{ + return m_MsgIn_()ReadBitCoord(); +} + +const Vector& CNetMsgScriptHelper::ReadVec3Coord() +{ + static Vector vec3; + //vec3.Init(); + m_MsgIn_()ReadBitVec3Coord(vec3); + return vec3; +} + +const Vector& CNetMsgScriptHelper::ReadVec3Normal() +{ + static Vector vec3; + //vec3.Init(); + m_MsgIn_()ReadBitVec3Normal(vec3); + return vec3; +} + +const QAngle& CNetMsgScriptHelper::ReadAngles() +{ + static QAngle vec3; + //vec3.Init(); + m_MsgIn_()ReadBitAngles(vec3); + return vec3; +} + +const char* CNetMsgScriptHelper::ReadString() +{ + static char buf[512]; + m_MsgIn_()ReadString( buf, sizeof(buf) ); + return buf; +} + +bool CNetMsgScriptHelper::ReadBool() +{ + return m_MsgIn_()ReadOneBit(); +} + +HSCRIPT CNetMsgScriptHelper::ReadEntity() +{ + int index = m_MsgIn_()ReadSBitLong( MAX_EDICT_BITS ); +#ifdef GAME_DLL + edict_t *e = INDEXENT(index); + if ( e && !e->IsFree() ) + { + return ToHScript( GetContainingEntity(e) ); + } +#else // CLIENT_DLL + if ( index < NUM_ENT_ENTRIES ) + { + return ToHScript( CBaseEntity::Instance(index) ); + } +#endif + return NULL; +} + +HSCRIPT CNetMsgScriptHelper::ReadEHandle() +{ + int iEncodedEHandle = m_MsgIn_()ReadLong(); + if ( iEncodedEHandle == INVALID_NETWORKED_EHANDLE_VALUE ) + return NULL; + int iEntry = iEncodedEHandle & ( (1 << MAX_EDICT_BITS) - 1 ); + int iSerialNum = iEncodedEHandle >> MAX_EDICT_BITS; + return ToHScript( EHANDLE( iEntry, iSerialNum ) ); +} + +int CNetMsgScriptHelper::GetNumBitsWritten() +{ + return m_MsgOut.GetNumBitsWritten(); +} + +#undef m_MsgIn_ + +BEGIN_SCRIPTDESC_ROOT_NAMED( CNetMsgScriptHelper, "CNetMsg", SCRIPT_SINGLETON "Network messages" ) + +#ifdef GAME_DLL + DEFINE_SCRIPTFUNC( SendUserMessage, "Send a usermessage from the server to the client" ) + DEFINE_SCRIPTFUNC( SendEntityMessage, "Send a message from a server side entity to its client side counterpart" ) + DEFINE_SCRIPTFUNC( AddRecipient, "" ) + DEFINE_SCRIPTFUNC( AddRecipientsByPVS, "" ) + DEFINE_SCRIPTFUNC( AddRecipientsByPAS, "" ) + DEFINE_SCRIPTFUNC( AddAllPlayers, "" ) +#else + DEFINE_SCRIPTFUNC( DispatchUserMessage, "Dispatch a usermessage on client" ) +#endif + + DEFINE_SCRIPTFUNC( Reset, "Reset the current network message buffer" ) + DEFINE_SCRIPTFUNC( Start, "Start writing new custom network message" ) + DEFINE_SCRIPTFUNC( Recieve, "Set custom network message callback" ) +#ifdef GAME_DLL + DEFINE_SCRIPTFUNC( Send, "Send a custom network message from the server to the client (max 252 bytes)" ) +#else + DEFINE_SCRIPTFUNC( Send, "Send a custom network message from the client to the server (max 2045 bytes)" ) +#endif + + DEFINE_SCRIPTFUNC( WriteInt, "" ) + DEFINE_SCRIPTFUNC( WriteUInt, "" ) + DEFINE_SCRIPTFUNC( WriteByte, "8 bit unsigned char" ) + DEFINE_SCRIPTFUNC( WriteChar, "8 bit char" ) + DEFINE_SCRIPTFUNC( WriteShort, "16 bit short" ) + DEFINE_SCRIPTFUNC( WriteWord, "16 bit unsigned short" ) + DEFINE_SCRIPTFUNC( WriteLong, "32 bit long" ) + DEFINE_SCRIPTFUNC( WriteFloat, "" ) + DEFINE_SCRIPTFUNC( WriteNormal, "12 bit" ) + DEFINE_SCRIPTFUNC( WriteAngle, "8 bit unsigned char" ) + DEFINE_SCRIPTFUNC( WriteCoord, "" ) + DEFINE_SCRIPTFUNC( WriteVec3Coord, "" ) + DEFINE_SCRIPTFUNC( WriteVec3Normal, "27 bit" ) + DEFINE_SCRIPTFUNC( WriteAngles, "" ) + DEFINE_SCRIPTFUNC( WriteString, "max 512 bytes at once" ) + DEFINE_SCRIPTFUNC( WriteBool, "1 bit" ) + DEFINE_SCRIPTFUNC( WriteEntity, "11 bit (entindex)" ) + DEFINE_SCRIPTFUNC( WriteEHandle, "32 bit long" ) + + DEFINE_SCRIPTFUNC( ReadInt, "" ) + DEFINE_SCRIPTFUNC( ReadUInt, "" ) + DEFINE_SCRIPTFUNC( ReadByte, "" ) + DEFINE_SCRIPTFUNC( ReadChar, "" ) + DEFINE_SCRIPTFUNC( ReadShort, "" ) + DEFINE_SCRIPTFUNC( ReadWord, "" ) + DEFINE_SCRIPTFUNC( ReadLong, "" ) + DEFINE_SCRIPTFUNC( ReadFloat, "" ) + DEFINE_SCRIPTFUNC( ReadNormal, "" ) + DEFINE_SCRIPTFUNC( ReadAngle, "" ) + DEFINE_SCRIPTFUNC( ReadCoord, "" ) + DEFINE_SCRIPTFUNC( ReadVec3Coord, "" ) + DEFINE_SCRIPTFUNC( ReadVec3Normal, "" ) + DEFINE_SCRIPTFUNC( ReadAngles, "" ) + DEFINE_SCRIPTFUNC( ReadString, "" ) + DEFINE_SCRIPTFUNC( ReadBool, "" ) + DEFINE_SCRIPTFUNC( ReadEntity, "" ) + DEFINE_SCRIPTFUNC( ReadEHandle, "" ) + + DEFINE_SCRIPTFUNC( GetNumBitsWritten, "" ) + +END_SCRIPTDESC(); + + + +#define RETURN_IF_CANNOT_DRAW_OVERLAY\ + if (engine->IsPaused())\ + {\ + CGWarning( 1, CON_GROUP_VSCRIPT, "debugoverlay: cannot draw while the game is paused!\n");\ + return;\ + } +class CDebugOverlayScriptHelper +{ +public: + + void Box( const Vector &origin, const Vector &mins, const Vector &maxs, int r, int g, int b, int a, float flDuration ) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + debugoverlay->AddBoxOverlay(origin, mins, maxs, vec3_angle, r, g, b, a, flDuration); + } + void BoxDirection( const Vector &origin, const Vector &mins, const Vector &maxs, const Vector &forward, int r, int g, int b, int a, float flDuration ) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + QAngle f_angles = vec3_angle; + f_angles.y = UTIL_VecToYaw(forward); + + debugoverlay->AddBoxOverlay(origin, mins, maxs, f_angles, r, g, b, a, flDuration); + } + void BoxAngles( const Vector &origin, const Vector &mins, const Vector &maxs, const QAngle &angles, int r, int g, int b, int a, float flDuration ) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + debugoverlay->AddBoxOverlay(origin, mins, maxs, angles, r, g, b, a, flDuration); + } + void SweptBox( const Vector& start, const Vector& end, const Vector& mins, const Vector& maxs, const QAngle & angles, int r, int g, int b, int a, float flDuration ) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + debugoverlay->AddSweptBoxOverlay(start, end, mins, maxs, angles, r, g, b, a, flDuration); + } + void EntityBounds( HSCRIPT pEntity, int r, int g, int b, int a, float flDuration ) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + CBaseEntity *pEnt = ToEnt(pEntity); + if (!pEnt) return; - } - CBaseEntity *pPlayer = ToEnt(player); - if ( pPlayer ) - { - filter.AddRecipient( (CBasePlayer*)pPlayer ); - } - - if ( bReliable ) - { - filter.MakeReliable(); - } - - SendMsg( engine->UserMessageBegin( &filter, msg_type ) ); + const CCollisionProperty *pCollide = pEnt->CollisionProp(); + debugoverlay->AddBoxOverlay(pCollide->GetCollisionOrigin(), pCollide->OBBMins(), pCollide->OBBMaxs(), pCollide->GetCollisionAngles(), r, g, b, a, flDuration); } - - void SendEntityMessage( HSCRIPT hEnt, bool bReliable ) + void Line( const Vector &origin, const Vector &target, int r, int g, int b, bool noDepthTest, float flDuration ) { - CBaseEntity *entity = ToEnt(hEnt); - if ( !entity ) + RETURN_IF_CANNOT_DRAW_OVERLAY + + debugoverlay->AddLineOverlay(origin, target, r, g, b, noDepthTest, flDuration); + } + void Triangle( const Vector &p1, const Vector &p2, const Vector &p3, int r, int g, int b, int a, bool noDepthTest, float duration ) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + debugoverlay->AddTriangleOverlay(p1, p2, p3, r, g, b, a, noDepthTest, duration); + } + void EntityText( int entityID, int text_offset, const char *text, float flDuration, int r, int g, int b, int a ) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + debugoverlay->AddEntityTextOverlay(entityID, text_offset, flDuration, + (int)clamp(r * 255.f, 0.f, 255.f), (int)clamp(g * 255.f, 0.f, 255.f), (int)clamp(b * 255.f, 0.f, 255.f), + (int)clamp(a * 255.f, 0.f, 255.f), text); + } + void EntityTextAtPosition( const Vector &origin, int text_offset, const char *text, float flDuration, int r, int g, int b, int a ) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + debugoverlay->AddTextOverlayRGB(origin, text_offset, flDuration, r, g, b, a, "%s", text); + } + void Grid( const Vector &vPosition ) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + debugoverlay->AddGridOverlay(vPosition); + } + void Text( const Vector &origin, const char *text, float flDuration ) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + debugoverlay->AddTextOverlay(origin, flDuration, "%s", text); + } + void ScreenText( float fXpos, float fYpos, const char *text, int r, int g, int b, int a, float flDuration ) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + debugoverlay->AddScreenTextOverlay(fXpos, fYpos, flDuration, r, g, b, a, text); + } + void Cross3D( const Vector &position, float size, int r, int g, int b, bool noDepthTest, float flDuration ) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + Line( position + Vector(size,0,0), position - Vector(size,0,0), r, g, b, noDepthTest, flDuration ); + Line( position + Vector(0,size,0), position - Vector(0,size,0), r, g, b, noDepthTest, flDuration ); + Line( position + Vector(0,0,size), position - Vector(0,0,size), r, g, b, noDepthTest, flDuration ); + } + void Cross3DOriented( const Vector &position, const QAngle &angles, float size, int r, int g, int b, bool noDepthTest, float flDuration ) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + Vector forward, right, up; + AngleVectors( angles, &forward, &right, &up ); + + forward *= size; + right *= size; + up *= size; + + Line( position + right, position - right, r, g, b, noDepthTest, flDuration ); + Line( position + forward, position - forward, r, g, b, noDepthTest, flDuration ); + Line( position + up, position - up, r, g, b, noDepthTest, flDuration ); + } + void DrawTickMarkedLine( const Vector &startPos, const Vector &endPos, float tickDist, int tickTextDist, int r, int g, int b, bool noDepthTest, float flDuration ) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + Vector lineDir = (endPos - startPos); + float lineDist = VectorNormalize(lineDir); + int numTicks = lineDist / tickDist; + + Vector upVec = Vector(0,0,4); + Vector sideDir; + Vector tickPos = startPos; + int tickTextCnt = 0; + + CrossProduct(lineDir, upVec, sideDir); + + Line(startPos, endPos, r, g, b, noDepthTest, flDuration); + + for (int i = 0; iRaiseException("EntityMessageBegin: invalid entity"); + Vector tickLeft = tickPos - sideDir; + Vector tickRight = tickPos + sideDir; + + if (tickTextCnt == tickTextDist) + { + char text[25]; + Q_snprintf(text, sizeof(text), "%i", i); + Vector textPos = tickLeft + Vector(0, 0, 8); + Line(tickLeft, tickRight, 255, 255, 255, noDepthTest, flDuration); + Text(textPos, text, flDuration); + tickTextCnt = 0; + } + else + { + Line(tickLeft, tickRight, r, g, b, noDepthTest, flDuration); + } + + tickTextCnt++; + + tickPos = tickPos + (tickDist * lineDir); + } + } + void HorzArrow( const Vector &startPos, const Vector &endPos, float width, int r, int g, int b, int a, bool noDepthTest, float flDuration ) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + Vector lineDir = (endPos - startPos); + VectorNormalize( lineDir ); + Vector upVec = Vector( 0, 0, 1 ); + Vector sideDir; + float radius = width / 2.0; + + CrossProduct(lineDir, upVec, sideDir); + + Vector p1 = startPos - sideDir * radius; + Vector p2 = endPos - lineDir * width - sideDir * radius; + Vector p3 = endPos - lineDir * width - sideDir * width; + Vector p4 = endPos; + Vector p5 = endPos - lineDir * width + sideDir * width; + Vector p6 = endPos - lineDir * width + sideDir * radius; + Vector p7 = startPos + sideDir * radius; + + Line(p1, p2, r,g,b,noDepthTest,flDuration); + Line(p2, p3, r,g,b,noDepthTest,flDuration); + Line(p3, p4, r,g,b,noDepthTest,flDuration); + Line(p4, p5, r,g,b,noDepthTest,flDuration); + Line(p5, p6, r,g,b,noDepthTest,flDuration); + Line(p6, p7, r,g,b,noDepthTest,flDuration); + + if ( a > 0 ) + { + Triangle( p5, p4, p3, r, g, b, a, noDepthTest, flDuration ); + Triangle( p1, p7, p6, r, g, b, a, noDepthTest, flDuration ); + Triangle( p6, p2, p1, r, g, b, a, noDepthTest, flDuration ); + + Triangle( p3, p4, p5, r, g, b, a, noDepthTest, flDuration ); + Triangle( p6, p7, p1, r, g, b, a, noDepthTest, flDuration ); + Triangle( p1, p2, p6, r, g, b, a, noDepthTest, flDuration ); + } + } + void YawArrow( const Vector &startPos, float yaw, float length, float width, int r, int g, int b, int a, bool noDepthTest, float flDuration ) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + Vector forward = UTIL_YawToVector( yaw ); + HorzArrow( startPos, startPos + forward * length, width, r, g, b, a, noDepthTest, flDuration ); + } + void VertArrow( const Vector &startPos, const Vector &endPos, float width, int r, int g, int b, int a, bool noDepthTest, float flDuration ) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + Vector lineDir = (endPos - startPos); + VectorNormalize( lineDir ); + Vector upVec; + Vector sideDir; + float radius = width / 2.0; + + VectorVectors( lineDir, sideDir, upVec ); + + Vector p1 = startPos - upVec * radius; + Vector p2 = endPos - lineDir * width - upVec * radius; + Vector p3 = endPos - lineDir * width - upVec * width; + Vector p4 = endPos; + Vector p5 = endPos - lineDir * width + upVec * width; + Vector p6 = endPos - lineDir * width + upVec * radius; + Vector p7 = startPos + upVec * radius; + + Line(p1, p2, r,g,b,noDepthTest,flDuration); + Line(p2, p3, r,g,b,noDepthTest,flDuration); + Line(p3, p4, r,g,b,noDepthTest,flDuration); + Line(p4, p5, r,g,b,noDepthTest,flDuration); + Line(p5, p6, r,g,b,noDepthTest,flDuration); + Line(p6, p7, r,g,b,noDepthTest,flDuration); + + if ( a > 0 ) + { + Triangle( p5, p4, p3, r, g, b, a, noDepthTest, flDuration ); + Triangle( p1, p7, p6, r, g, b, a, noDepthTest, flDuration ); + Triangle( p6, p2, p1, r, g, b, a, noDepthTest, flDuration ); + + Triangle( p3, p4, p5, r, g, b, a, noDepthTest, flDuration ); + Triangle( p6, p7, p1, r, g, b, a, noDepthTest, flDuration ); + Triangle( p1, p2, p6, r, g, b, a, noDepthTest, flDuration ); + } + } + void Axis( const Vector &position, const QAngle &angles, float size, bool noDepthTest, float flDuration ) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + Vector xvec, yvec, zvec; + AngleVectors( angles, &xvec, &yvec, &zvec ); + + xvec = position + (size * xvec); + yvec = position - (size * yvec); + zvec = position + (size * zvec); + + Line( position, xvec, 255, 0, 0, noDepthTest, flDuration ); + Line( position, yvec, 0, 255, 0, noDepthTest, flDuration ); + Line( position, zvec, 0, 0, 255, noDepthTest, flDuration ); + } + void Sphere( const Vector ¢er, float radius, int r, int g, int b, bool noDepthTest, float flDuration ) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + Vector edge, lastEdge; + + float axisSize = radius; + Line( center + Vector( 0, 0, -axisSize ), center + Vector( 0, 0, axisSize ), r, g, b, noDepthTest, flDuration ); + Line( center + Vector( 0, -axisSize, 0 ), center + Vector( 0, axisSize, 0 ), r, g, b, noDepthTest, flDuration ); + Line( center + Vector( -axisSize, 0, 0 ), center + Vector( axisSize, 0, 0 ), r, g, b, noDepthTest, flDuration ); + + lastEdge = Vector( radius + center.x, center.y, center.z ); + float angle; + for( angle=0.0f; angle <= 360.0f; angle += 22.5f ) + { + edge.x = radius * cosf( angle / 180.0f * M_PI ) + center.x; + edge.y = center.y; + edge.z = radius * sinf( angle / 180.0f * M_PI ) + center.z; + + Line( edge, lastEdge, r, g, b, noDepthTest, flDuration ); + + lastEdge = edge; + } + + lastEdge = Vector( center.x, radius + center.y, center.z ); + for( angle=0.0f; angle <= 360.0f; angle += 22.5f ) + { + edge.x = center.x; + edge.y = radius * cosf( angle / 180.0f * M_PI ) + center.y; + edge.z = radius * sinf( angle / 180.0f * M_PI ) + center.z; + + Line( edge, lastEdge, r, g, b, noDepthTest, flDuration ); + + lastEdge = edge; + } + + lastEdge = Vector( center.x, radius + center.y, center.z ); + for( angle=0.0f; angle <= 360.0f; angle += 22.5f ) + { + edge.x = radius * cosf( angle / 180.0f * M_PI ) + center.x; + edge.y = radius * sinf( angle / 180.0f * M_PI ) + center.y; + edge.z = center.z; + + Line( edge, lastEdge, r, g, b, noDepthTest, flDuration ); + + lastEdge = edge; + } + } + void CircleOriented( const Vector &position, const QAngle &angles, float radius, int r, int g, int b, int a, bool bNoDepthTest, float flDuration ) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + matrix3x4_t xform; + AngleMatrix(angles, position, xform); + Vector xAxis, yAxis; + MatrixGetColumn(xform, 2, xAxis); + MatrixGetColumn(xform, 1, yAxis); + Circle(position, xAxis, yAxis, radius, r, g, b, a, bNoDepthTest, flDuration); + } + void Circle( const Vector &position, const Vector &xAxis, const Vector &yAxis, float radius, int r, int g, int b, int a, bool bNoDepthTest, float flDuration ) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + const unsigned int nSegments = 16; + const float flRadStep = (M_PI*2.0f) / (float) nSegments; + + Vector vecLastPosition; + Vector vecStart = position + xAxis * radius; + Vector vecPosition = vecStart; + + for ( int i = 1; i <= nSegments; i++ ) + { + vecLastPosition = vecPosition; + + float flSin, flCos; + SinCos( flRadStep*i, &flSin, &flCos ); + vecPosition = position + (xAxis * flCos * radius) + (yAxis * flSin * radius); + + Line( vecLastPosition, vecPosition, r, g, b, bNoDepthTest, flDuration ); + + if ( a && i > 1 ) + { + debugoverlay->AddTriangleOverlay( vecStart, vecLastPosition, vecPosition, r, g, b, a, bNoDepthTest, flDuration ); + } + } + } +#ifndef CLIENT_DLL + void SetDebugBits( HSCRIPT hEntity, int bit ) // DebugOverlayBits_t + { + CBaseEntity *pEnt = ToEnt(hEntity); + if (!pEnt) return; - } - SendMsg( engine->EntityMessageBegin( entity->entindex(), entity->GetServerClass(), bReliable ) ); - } - -public: - void AddRecipient( HSCRIPT player ) - { - CBaseEntity *pPlayer = ToEnt(player); - if ( pPlayer ) + if (pEnt->m_debugOverlays & bit) { - filter.AddRecipient( (CBasePlayer*)pPlayer ); - } - } - - void AddRecipientsByPVS( const Vector &pos ) - { - filter.AddRecipientsByPVS(pos); - } - - void AddAllPlayers() - { - filter.AddAllPlayers(); - } - -public: - void WriteByte( int iValue ) { message.WriteByte( iValue ); } - void WriteChar( int iValue ) { message.WriteChar( iValue ); } - void WriteShort( int iValue ) { message.WriteShort( iValue ); } - void WriteWord( int iValue ) { message.WriteWord( iValue ); } - void WriteLong( int iValue ) { message.WriteLong( iValue ); } - void WriteFloat( float flValue ) { message.WriteFloat( flValue ); } - void WriteAngle( float flValue ) { message.WriteBitAngle( flValue, 8 ); } - void WriteCoord( float flValue ) { message.WriteBitCoord( flValue ); } - void WriteVec3Coord( const Vector& rgflValue ) { message.WriteBitVec3Coord( rgflValue ); } - void WriteVec3Normal( const Vector& rgflValue ) { message.WriteBitVec3Normal( rgflValue ); } - void WriteAngles( const QAngle& rgflValue ) { message.WriteBitAngles( rgflValue ); } - void WriteString( const char *sz ) { message.WriteString( sz ); } - void WriteEntity( int iValue ) { message.WriteShort( iValue ); } - void WriteBool( bool bValue ) { message.WriteOneBit( bValue ? 1 : 0 ); } - void WriteEHandle( HSCRIPT hEnt ) - { - CBaseEntity *pEnt = ToEnt( hEnt ); - long iEncodedEHandle; - if ( pEnt ) - { - EHANDLE hEnt = pEnt; - int iSerialNum = hEnt.GetSerialNumber() & (1 << NUM_NETWORKED_EHANDLE_SERIAL_NUMBER_BITS) - 1; - iEncodedEHandle = hEnt.GetEntryIndex() | (iSerialNum << MAX_EDICT_BITS); + pEnt->m_debugOverlays &= ~bit; } else { - iEncodedEHandle = INVALID_NETWORKED_EHANDLE_VALUE; + pEnt->m_debugOverlays |= bit; + +#ifdef AI_MONITOR_FOR_OSCILLATION + if (pEnt->IsNPC()) + { + pEnt->MyNPCPointer()->m_ScheduleHistory.RemoveAll(); + } +#endif//AI_MONITOR_FOR_OSCILLATION } - message.WriteLong( iEncodedEHandle ); + } +#endif + void ClearAllOverlays() + { +#ifndef CLIENT_DLL + // Clear all entities of their debug overlays + for (CBaseEntity *pEntity = gEntList.FirstEnt(); pEntity; pEntity = gEntList.NextEnt(pEntity)) + { + pEntity->m_debugOverlays = 0; + } +#endif + + debugoverlay->ClearAllOverlays(); } -} g_ScriptNetMsg; +private: +} g_ScriptDebugOverlay; -BEGIN_SCRIPTDESC_ROOT_NAMED( CNetMsgScriptHelper, "CNetMsg", SCRIPT_SINGLETON "NetworkMessages" ) - DEFINE_SCRIPTFUNC( Reset, "" ) - DEFINE_SCRIPTFUNC( SendUserMessage, "" ) - DEFINE_SCRIPTFUNC( SendEntityMessage, "" ) - DEFINE_SCRIPTFUNC( AddRecipient, "" ) - DEFINE_SCRIPTFUNC( AddRecipientsByPVS, "" ) - DEFINE_SCRIPTFUNC( AddAllPlayers, "" ) - DEFINE_SCRIPTFUNC( WriteByte, "" ) - DEFINE_SCRIPTFUNC( WriteChar, "" ) - DEFINE_SCRIPTFUNC( WriteShort, "" ) - DEFINE_SCRIPTFUNC( WriteWord, "" ) - DEFINE_SCRIPTFUNC( WriteLong, "" ) - DEFINE_SCRIPTFUNC( WriteFloat, "" ) - DEFINE_SCRIPTFUNC( WriteAngle, "" ) - DEFINE_SCRIPTFUNC( WriteCoord, "" ) - DEFINE_SCRIPTFUNC( WriteVec3Coord, "" ) - DEFINE_SCRIPTFUNC( WriteVec3Normal, "" ) - DEFINE_SCRIPTFUNC( WriteAngles, "" ) - DEFINE_SCRIPTFUNC( WriteString, "" ) - DEFINE_SCRIPTFUNC( WriteEntity, "" ) - DEFINE_SCRIPTFUNC( WriteEHandle, "" ) - DEFINE_SCRIPTFUNC( WriteBool, "" ) +BEGIN_SCRIPTDESC_ROOT( CDebugOverlayScriptHelper, SCRIPT_SINGLETON "CDebugOverlayScriptHelper" ) + DEFINE_SCRIPTFUNC( Box, "Draws a world-space axis-aligned box. Specify bounds in world space." ) + DEFINE_SCRIPTFUNC( BoxDirection, "Draw box oriented to a Vector direction" ) + DEFINE_SCRIPTFUNC( BoxAngles, "Draws an oriented box at the origin. Specify bounds in local space." ) + DEFINE_SCRIPTFUNC( SweptBox, "Draws a swept box. Specify endpoints in world space and the bounds in local space." ) + DEFINE_SCRIPTFUNC( EntityBounds, "Draws bounds of an entity" ) + DEFINE_SCRIPTFUNC( Line, "Draws a line between two points" ) + DEFINE_SCRIPTFUNC( Triangle, "Draws a filled triangle. Specify vertices in world space." ) + DEFINE_SCRIPTFUNC( EntityText, "Draws text on an entity" ) + DEFINE_SCRIPTFUNC( EntityTextAtPosition, "Draw entity text overlay at a specific position" ) + DEFINE_SCRIPTFUNC( Grid, "Add grid overlay" ) + DEFINE_SCRIPTFUNC( Text, "Draws 2D text. Specify origin in world space." ) + DEFINE_SCRIPTFUNC( ScreenText, "Draws 2D text. Specify coordinates in screen space." ) + DEFINE_SCRIPTFUNC( Cross3D, "Draws a world-aligned cross. Specify origin in world space." ) + DEFINE_SCRIPTFUNC( Cross3DOriented, "Draws an oriented cross. Specify origin in world space." ) + DEFINE_SCRIPTFUNC( DrawTickMarkedLine, "Draws a dashed line. Specify endpoints in world space." ) + DEFINE_SCRIPTFUNC( HorzArrow, "Draws a horizontal arrow. Specify endpoints in world space." ) + DEFINE_SCRIPTFUNC( YawArrow, "Draws a arrow associated with a specific yaw. Specify endpoints in world space." ) + DEFINE_SCRIPTFUNC( VertArrow, "Draws a vertical arrow. Specify endpoints in world space." ) + DEFINE_SCRIPTFUNC( Axis, "Draws an axis. Specify origin + orientation in world space." ) + DEFINE_SCRIPTFUNC( Sphere, "Draws a wireframe sphere. Specify center in world space." ) + DEFINE_SCRIPTFUNC( CircleOriented, "Draws a circle oriented. Specify center in world space." ) + DEFINE_SCRIPTFUNC( Circle, "Draws a circle. Specify center in world space." ) +#ifndef CLIENT_DLL + DEFINE_SCRIPTFUNC( SetDebugBits, "Set debug bits on entity" ) +#endif + DEFINE_SCRIPTFUNC( ClearAllOverlays, "Clear all debug overlays at once" ) END_SCRIPTDESC(); -#endif // !CLIENT_DLL + void RegisterScriptSingletons() { ScriptRegisterFunctionNamed( g_pScriptVM, CScriptSaveRestoreUtil::SaveTable, "SaveTable", "Store a table with primitive values that will persist across level transitions and save loads." ); ScriptRegisterFunctionNamed( g_pScriptVM, CScriptSaveRestoreUtil::RestoreTable, "RestoreTable", "Retrieves a table from storage. Write into input table." ); ScriptRegisterFunctionNamed( g_pScriptVM, CScriptSaveRestoreUtil::ClearSavedTable, "ClearSavedTable", "Removes the table with the given context." ); - ScriptRegisterFunctionNamed( g_pScriptVM, CScriptReadWriteFile::ScriptFileWrite, "StringToFile", "Stores the string into the file" ); - ScriptRegisterFunctionNamed( g_pScriptVM, CScriptReadWriteFile::ScriptFileRead, "FileToString", "Returns the string from the file, null if no file or file is too big." ); - ScriptRegisterFunctionNamed( g_pScriptVM, CScriptReadWriteFile::ScriptKeyValuesWrite, "KeyValuesToFile", "Stores the CScriptKeyValues into the file" ); - ScriptRegisterFunctionNamed( g_pScriptVM, CScriptReadWriteFile::ScriptKeyValuesRead, "FileToKeyValues", "Returns the CScriptKeyValues from the file, null if no file or file is too big." ); + ScriptRegisterFunctionNamed( g_pScriptVM, CScriptReadWriteFile::FileWrite, "StringToFile", "Stores the string into the file" ); + ScriptRegisterFunctionNamed( g_pScriptVM, CScriptReadWriteFile::FileRead, "FileToString", "Returns the string from the file, null if no file or file is too big." ); + ScriptRegisterFunctionNamed( g_pScriptVM, CScriptReadWriteFile::KeyValuesWrite, "KeyValuesToFile", "Stores the CScriptKeyValues into the file" ); + ScriptRegisterFunctionNamed( g_pScriptVM, CScriptReadWriteFile::KeyValuesRead, "FileToKeyValues", "Returns the CScriptKeyValues from the file, null if no file or file is too big." ); ScriptRegisterFunction( g_pScriptVM, ListenToGameEvent, "Register as a listener for a game event from script." ); ScriptRegisterFunctionNamed( g_pScriptVM, CScriptGameEventListener::StopListeningToGameEvent, "StopListeningToGameEvent", "Stop the specified event listener." ); @@ -1339,9 +2055,8 @@ void RegisterScriptSingletons() g_pScriptVM->RegisterInstance( &g_ScriptNetPropManager, "NetProps" ); g_pScriptVM->RegisterInstance( &g_ScriptLocalize, "Localize" ); -#ifndef CLIENT_DLL - g_pScriptVM->RegisterInstance( &g_ScriptNetMsg, "NetMsg" ); -#endif + g_pScriptVM->RegisterInstance( g_ScriptNetMsg, "NetMsg" ); + g_pScriptVM->RegisterInstance( &g_ScriptDebugOverlay, "debugoverlay" ); // Singletons not unique to VScript (not declared or defined here) g_pScriptVM->RegisterInstance( GameRules(), "GameRules" ); @@ -1353,4 +2068,6 @@ void RegisterScriptSingletons() #ifndef CLIENT_DLL CScriptGameEventListener::LoadAllEvents(); #endif // !CLIENT_DLL + + g_ScriptNetMsg->InitPostVM(); } diff --git a/sp/src/game/shared/mapbase/vscript_singletons.h b/sp/src/game/shared/mapbase/vscript_singletons.h index b190fe45..7e250c8b 100644 --- a/sp/src/game/shared/mapbase/vscript_singletons.h +++ b/sp/src/game/shared/mapbase/vscript_singletons.h @@ -5,12 +5,135 @@ // $NoKeywords: $ //============================================================================= -#ifndef VSCRIPT_FUNCS_MATH -#define VSCRIPT_FUNCS_MATH +#ifndef VSCRIPT_SINGLETONS +#define VSCRIPT_SINGLETONS #ifdef _WIN32 #pragma once #endif void RegisterScriptSingletons(); + + +#ifdef CLIENT_DLL +// usercmd +#define SCRIPT_NETMSG_DATA_SIZE ( ( 1 << 11 ) - 1 ) +#else +// usermsg +#define SCRIPT_NETMSG_DATA_SIZE MAX_USER_MSG_DATA +#endif + +#ifdef CLIENT_DLL +class CNetMsgScriptHelper : public CAutoGameSystem +#else +class CNetMsgScriptHelper +#endif +{ +private: +#ifdef GAME_DLL + CRecipientFilter m_filter; + bf_read *m_MsgIn; +#else + bf_read m_MsgIn; +#endif + bf_write m_MsgOut; + byte m_MsgData[ PAD_NUMBER( SCRIPT_NETMSG_DATA_SIZE, 4 ) ]; + HSCRIPT m_Hooks; + +public: +#ifdef CLIENT_DLL + bool m_bWriteReady; // dt ready to send + + CNetMsgScriptHelper() : m_Hooks(NULL), m_bWriteReady(false) {} +#else + CNetMsgScriptHelper() : m_Hooks(NULL) {} +#endif + +public: +#ifdef CLIENT_DLL + bool Init(); // IGameSystem + static void __MsgFunc_ScriptMsg( bf_read &msg ); +#endif + void LevelShutdownPreVM(); // Executed in CVScriptGameSystem + void InitPostVM(); + +#ifdef GAME_DLL + void RecieveMessage( bf_read *msg, CBaseEntity *pPlayer ); +#else + void RecieveMessage( bf_read &msg ); +#endif + void WriteToBuffer( bf_write *bf ); + +public: + inline void Reset(); + void Start( const char *msg ); +#ifdef GAME_DLL + void Send( HSCRIPT player, bool bReliable ); +#else + void Send(); +#endif + void Recieve( const char *msg, HSCRIPT func ); + +#ifdef GAME_DLL + inline void DoSendUserMsg( CRecipientFilter *filter, int type ); + inline void DoSendEntityMsg( CBaseEntity *entity, bool reliable ); + + void SendUserMessage( HSCRIPT hPlayer, const char *msg, bool bReliable ); + void SendEntityMessage( HSCRIPT hEnt, bool bReliable ); +#else // CLIENT_DLL + void DispatchUserMessage( const char *msg ); +#endif + +#ifdef GAME_DLL +public: + void AddRecipient( HSCRIPT player ); + void AddRecipientsByPVS( const Vector &pos ); + void AddRecipientsByPAS( const Vector &pos ); + void AddAllPlayers(); +#endif // GAME_DLL + +public: + void WriteInt( int iValue, int bits ); + void WriteUInt( int iValue, int bits ); + void WriteByte( int iValue ); // 8 bit unsigned char + void WriteChar( int iValue ); // 8 bit char + void WriteShort( int iValue ); // 16 bit short + void WriteWord( int iValue ); // 16 bit unsigned short + void WriteLong( int iValue ); // 32 bit long + void WriteFloat( float flValue ); + void WriteNormal( float flValue ); // 12 bit + void WriteAngle( float flValue ); // 8 bit unsigned char + void WriteCoord( float flValue ); + void WriteVec3Coord( const Vector& rgflValue ); + void WriteVec3Normal( const Vector& rgflValue ); // 27 bit ( 3 + 2 * (1 + NORMAL_FRACTIONAL_BITS) ) + void WriteAngles( const QAngle& rgflValue ); + void WriteString( const char *sz ); // max 512 bytes at once + void WriteBool( bool bValue ); // 1 bit + void WriteEntity( HSCRIPT hEnt ); // 11 bit (entindex) + void WriteEHandle( HSCRIPT hEnt ); // 32 bit long + int ReadInt( int bits ); + int ReadUInt( int bits ); + int ReadByte(); + int ReadChar(); + int ReadShort(); + int ReadWord(); + int ReadLong(); + float ReadFloat(); + float ReadNormal(); + float ReadAngle(); + float ReadCoord(); + const Vector& ReadVec3Coord(); + const Vector& ReadVec3Normal(); + const QAngle& ReadAngles(); + const char* ReadString(); + bool ReadBool(); + HSCRIPT ReadEntity(); + HSCRIPT ReadEHandle(); + //int GetNumBitsLeft(); // unreliable on server because of usercmds. so just do away with it + int GetNumBitsWritten(); + +}; + +extern CNetMsgScriptHelper *g_ScriptNetMsg; + #endif diff --git a/sp/src/game/shared/usercmd.cpp b/sp/src/game/shared/usercmd.cpp index 84ffa243..032b366c 100644 --- a/sp/src/game/shared/usercmd.cpp +++ b/sp/src/game/shared/usercmd.cpp @@ -10,12 +10,20 @@ #include "bitbuf.h" #include "checksum_md5.h" +#ifdef MAPBASE_VSCRIPT +#include "mapbase/vscript_singletons.h" +#endif + // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" // TF2 specific, need enough space for OBJ_LAST items from tf_shareddefs.h #define WEAPON_SUBTYPE_BITS 6 +#ifdef MAPBASE_VSCRIPT +extern CNetMsgScriptHelper *g_ScriptNetMsg; +#endif + //----------------------------------------------------------------------------- // Purpose: Write a delta compressed user command. // Input : *buf - @@ -187,6 +195,22 @@ void WriteUsercmd( bf_write *buf, const CUserCmd *to, const CUserCmd *from ) buf->WriteOneBit( 0 ); } #endif + +#if defined( MAPBASE_VSCRIPT ) && defined( CLIENT_DLL ) + Assert( g_ScriptNetMsg ); + + if ( g_ScriptNetMsg->m_bWriteReady ) + { + buf->WriteOneBit( 1 ); + g_ScriptNetMsg->WriteToBuffer( buf ); + g_ScriptNetMsg->m_bWriteReady = false; + } + else + { + buf->WriteOneBit( 0 ); + } +#endif + } //----------------------------------------------------------------------------- @@ -196,7 +220,11 @@ void WriteUsercmd( bf_write *buf, const CUserCmd *to, const CUserCmd *from ) // *from - // Output : static void ReadUsercmd //----------------------------------------------------------------------------- +#if defined( MAPBASE_VSCRIPT ) && defined( GAME_DLL ) +void ReadUsercmd( bf_read *buf, CUserCmd *move, CUserCmd *from, CBaseEntity *pPlayer ) +#else void ReadUsercmd( bf_read *buf, CUserCmd *move, CUserCmd *from ) +#endif { // Assume no change *move = *from; @@ -303,4 +331,12 @@ void ReadUsercmd( bf_read *buf, CUserCmd *move, CUserCmd *from ) } } #endif + +#if defined( MAPBASE_VSCRIPT ) && defined( GAME_DLL ) + if ( buf->ReadOneBit() ) + { + g_ScriptNetMsg->RecieveMessage( buf, pPlayer ); + } +#endif + } diff --git a/sp/src/game/shared/usercmd.h b/sp/src/game/shared/usercmd.h index 70afaebd..6b87f888 100644 --- a/sp/src/game/shared/usercmd.h +++ b/sp/src/game/shared/usercmd.h @@ -198,7 +198,11 @@ public: }; +#if defined( MAPBASE_VSCRIPT ) && defined( GAME_DLL ) +void ReadUsercmd( bf_read *buf, CUserCmd *move, CUserCmd *from, CBaseEntity *pPlayer ); +#else void ReadUsercmd( bf_read *buf, CUserCmd *move, CUserCmd *from ); +#endif void WriteUsercmd( bf_write *buf, const CUserCmd *to, const CUserCmd *from ); #endif // USERCMD_H diff --git a/sp/src/game/shared/vscript_shared.cpp b/sp/src/game/shared/vscript_shared.cpp index ebe997a8..eb7080a5 100644 --- a/sp/src/game/shared/vscript_shared.cpp +++ b/sp/src/game/shared/vscript_shared.cpp @@ -142,6 +142,9 @@ bool VScriptRunScript( const char *pszScriptName, HSCRIPT hScope, bool bWarnMiss bool bSuccess = false; if ( hScript ) { + // player is not yet spawned, this block is always skipped. + // It is registered in CBasePlayer instead. +#ifndef MAPBASE #ifdef GAME_DLL if ( gpGlobals->maxClients == 1 ) { @@ -151,6 +154,7 @@ bool VScriptRunScript( const char *pszScriptName, HSCRIPT hScope, bool bWarnMiss g_pScriptVM->SetValue( "player", pPlayer->GetScriptInstance() ); } } +#endif #endif bSuccess = ( g_pScriptVM->Run( hScript, hScope ) != SCRIPT_ERROR ); if ( !bSuccess ) @@ -262,7 +266,7 @@ CON_COMMAND_SHARED( script_help, "Output help for script functions, optionally w pszArg1 = args[1]; } - g_pScriptVM->Run( CFmtStr( "PrintHelp( \"%s\" );", pszArg1 ) ); + g_pScriptVM->Run( CFmtStr( "__Documentation.PrintHelp( \"%s\" );", pszArg1 ) ); } CON_COMMAND_SHARED( script_dump_all, "Dump the state of the VM to the console" ) diff --git a/sp/src/public/vscript/ivscript.h b/sp/src/public/vscript/ivscript.h index fb3a1b79..6cf8d462 100644 --- a/sp/src/public/vscript/ivscript.h +++ b/sp/src/public/vscript/ivscript.h @@ -762,6 +762,9 @@ struct ScriptEnumDesc_t #define DEFINE_SCRIPTHOOK_PARAM( paramName, type ) pHook->AddParameter( paramName, type ); +// Define actual parameters instead of global variables +#define DEFINE_SCRIPTHOOK_REALPARAM( paramName, type ) + #define END_SCRIPTHOOK() \ pDesc->m_Hooks.AddToTail(pHook); \ } @@ -932,6 +935,9 @@ public: virtual bool SetValue( HSCRIPT hScope, const char *pszKey, const char *pszValue ) = 0; virtual bool SetValue( HSCRIPT hScope, const char *pszKey, const ScriptVariant_t &value ) = 0; bool SetValue( const char *pszKey, const ScriptVariant_t &value ) { return SetValue(NULL, pszKey, value ); } +#ifdef MAPBASE_VSCRIPT + virtual bool SetValue( HSCRIPT hScope, const ScriptVariant_t& key, const ScriptVariant_t& val ) = 0; +#endif virtual void CreateTable( ScriptVariant_t &Table ) = 0; virtual int GetNumTableEntries( HSCRIPT hScope ) = 0; @@ -939,10 +945,16 @@ public: virtual bool GetValue( HSCRIPT hScope, const char *pszKey, ScriptVariant_t *pValue ) = 0; bool GetValue( const char *pszKey, ScriptVariant_t *pValue ) { return GetValue(NULL, pszKey, pValue ); } +#ifdef MAPBASE_VSCRIPT + virtual bool GetValue( HSCRIPT hScope, ScriptVariant_t key, ScriptVariant_t* pValue ) = 0; +#endif virtual void ReleaseValue( ScriptVariant_t &value ) = 0; virtual bool ClearValue( HSCRIPT hScope, const char *pszKey ) = 0; bool ClearValue( const char *pszKey) { return ClearValue( NULL, pszKey ); } +#ifdef MAPBASE_VSCRIPT + virtual bool ClearValue( HSCRIPT hScope, ScriptVariant_t pKey ) = 0; +#endif #ifdef MAPBASE_VSCRIPT // virtual void CreateArray(ScriptVariant_t &arr, int size = 0) = 0; diff --git a/sp/src/vscript/vscript_squirrel.cpp b/sp/src/vscript/vscript_squirrel.cpp index a6975fc7..2c80041b 100644 --- a/sp/src/vscript/vscript_squirrel.cpp +++ b/sp/src/vscript/vscript_squirrel.cpp @@ -31,7 +31,6 @@ #include "squirrel/squirrel/sqvm.h" #include "squirrel/squirrel/sqclosure.h" -#include "color.h" #include "tier1/utlbuffer.h" #include "tier1/mapbase_con_groups.h" @@ -202,15 +201,18 @@ public: virtual bool SetValue(HSCRIPT hScope, const char* pszKey, const char* pszValue) override; virtual bool SetValue(HSCRIPT hScope, const char* pszKey, const ScriptVariant_t& value) override; + virtual bool SetValue(HSCRIPT hScope, const ScriptVariant_t& key, const ScriptVariant_t& val) override; virtual void CreateTable(ScriptVariant_t& Table) override; virtual int GetNumTableEntries(HSCRIPT hScope) override; virtual int GetKeyValue(HSCRIPT hScope, int nIterator, ScriptVariant_t* pKey, ScriptVariant_t* pValue) override; virtual bool GetValue(HSCRIPT hScope, const char* pszKey, ScriptVariant_t* pValue) override; + virtual bool GetValue(HSCRIPT hScope, ScriptVariant_t key, ScriptVariant_t* pValue) override; virtual void ReleaseValue(ScriptVariant_t& value) override; virtual bool ClearValue(HSCRIPT hScope, const char* pszKey) override; + virtual bool ClearValue( HSCRIPT hScope, ScriptVariant_t pKey ) override; // virtual void CreateArray(ScriptVariant_t &arr, int size = 0) override; virtual bool ArrayAppend(HSCRIPT hArray, const ScriptVariant_t &val) override; @@ -1418,6 +1420,19 @@ const char * ScriptDataTypeToName(ScriptDataType_t datatype) } } + +#define PushDocumentationRegisterFunction( szName ) \ + sq_pushroottable(vm); \ + sq_pushstring(vm, "__Documentation", -1); \ + sq_get(vm, -2); \ + sq_pushstring(vm, szName, -1); \ + sq_get(vm, -2); \ + sq_push(vm, -2); + +#define CallDocumentationRegisterFunction( paramcount ) \ + sq_call(vm, paramcount+1, SQFalse, SQFalse); \ + sq_pop(vm, 3); + void RegisterDocumentation(HSQUIRRELVM vm, const ScriptFuncDescriptor_t& pFuncDesc, ScriptClassDesc_t* pClassDesc = nullptr) { SquirrelSafeCheck safeCheck(vm); @@ -1450,16 +1465,11 @@ void RegisterDocumentation(HSQUIRRELVM vm, const ScriptFuncDescriptor_t& pFuncDe V_strcat_safe(signature, ")"); // RegisterHelp(name, signature, description) - sq_pushroottable(vm); - sq_pushstring(vm, "RegisterHelp", -1); - sq_get(vm, -2); - sq_remove(vm, -2); - sq_pushroottable(vm); - sq_pushstring(vm, name, -1); - sq_pushstring(vm, signature, -1); - sq_pushstring(vm, pFuncDesc.m_pszDescription ? pFuncDesc.m_pszDescription : "", -1); - sq_call(vm, 4, SQFalse, SQFalse); - sq_pop(vm, 1); + PushDocumentationRegisterFunction( "RegisterHelp" ); + sq_pushstring(vm, name, -1); + sq_pushstring(vm, signature, -1); + sq_pushstring(vm, pFuncDesc.m_pszDescription ? pFuncDesc.m_pszDescription : "", -1); + CallDocumentationRegisterFunction( 3 ); } void RegisterClassDocumentation(HSQUIRRELVM vm, const ScriptClassDesc_t* pClassDesc) @@ -1487,16 +1497,11 @@ void RegisterClassDocumentation(HSQUIRRELVM vm, const ScriptClassDesc_t* pClassD } // RegisterClassHelp(name, base, description) - sq_pushroottable(vm); - sq_pushstring(vm, "RegisterClassHelp", -1); - sq_get(vm, -2); - sq_remove(vm, -2); - sq_pushroottable(vm); - sq_pushstring(vm, name, -1); - sq_pushstring(vm, base, -1); - sq_pushstring(vm, description, -1); - sq_call(vm, 4, SQFalse, SQFalse); - sq_pop(vm, 1); + PushDocumentationRegisterFunction( "RegisterClassHelp" ); + sq_pushstring(vm, name, -1); + sq_pushstring(vm, base, -1); + sq_pushstring(vm, description, -1); + CallDocumentationRegisterFunction( 3 ); } void RegisterEnumDocumentation(HSQUIRRELVM vm, const ScriptEnumDesc_t* pClassDesc) @@ -1509,16 +1514,11 @@ void RegisterEnumDocumentation(HSQUIRRELVM vm, const ScriptEnumDesc_t* pClassDes const char *name = pClassDesc->m_pszScriptName; // RegisterEnumHelp(name, description) - sq_pushroottable(vm); - sq_pushstring(vm, "RegisterEnumHelp", -1); - sq_get(vm, -2); - sq_remove(vm, -2); - sq_pushroottable(vm); - sq_pushstring(vm, name, -1); - sq_pushinteger(vm, pClassDesc->m_ConstantBindings.Count()); - sq_pushstring(vm, pClassDesc->m_pszDescription ? pClassDesc->m_pszDescription : "", -1); - sq_call(vm, 4, SQFalse, SQFalse); - sq_pop(vm, 1); + PushDocumentationRegisterFunction( "RegisterEnumHelp" ); + sq_pushstring(vm, name, -1); + sq_pushinteger(vm, pClassDesc->m_ConstantBindings.Count()); + sq_pushstring(vm, pClassDesc->m_pszDescription ? pClassDesc->m_pszDescription : "", -1); + CallDocumentationRegisterFunction( 3 ); } void RegisterConstantDocumentation( HSQUIRRELVM vm, const ScriptConstantBinding_t* pConstDesc, const char *pszAsString, ScriptEnumDesc_t* pEnumDesc = nullptr ) @@ -1542,16 +1542,11 @@ void RegisterConstantDocumentation( HSQUIRRELVM vm, const ScriptConstantBinding_ V_snprintf(signature, sizeof(signature), "%s (%s)", pszAsString, ScriptDataTypeToName(pConstDesc->m_data.m_type)); // RegisterConstHelp(name, signature, description) - sq_pushroottable(vm); - sq_pushstring(vm, "RegisterConstHelp", -1); - sq_get(vm, -2); - sq_remove(vm, -2); - sq_pushroottable(vm); - sq_pushstring(vm, name, -1); - sq_pushstring(vm, signature, -1); - sq_pushstring(vm, pConstDesc->m_pszDescription ? pConstDesc->m_pszDescription : "", -1); - sq_call(vm, 4, SQFalse, SQFalse); - sq_pop(vm, 1); + PushDocumentationRegisterFunction( "RegisterConstHelp" ); + sq_pushstring(vm, name, -1); + sq_pushstring(vm, signature, -1); + sq_pushstring(vm, pConstDesc->m_pszDescription ? pConstDesc->m_pszDescription : "", -1); + CallDocumentationRegisterFunction( 3 ); } void RegisterHookDocumentation(HSQUIRRELVM vm, const ScriptHook_t* pHook, const ScriptFuncDescriptor_t& pFuncDesc, ScriptClassDesc_t* pClassDesc = nullptr) @@ -1589,16 +1584,11 @@ void RegisterHookDocumentation(HSQUIRRELVM vm, const ScriptHook_t* pHook, const V_strcat_safe(signature, ")"); // RegisterHookHelp(name, signature, description) - sq_pushroottable(vm); - sq_pushstring(vm, "RegisterHookHelp", -1); - sq_get(vm, -2); - sq_remove(vm, -2); - sq_pushroottable(vm); - sq_pushstring(vm, name, -1); - sq_pushstring(vm, signature, -1); - sq_pushstring(vm, pFuncDesc.m_pszDescription ? pFuncDesc.m_pszDescription : "", -1); - sq_call(vm, 4, SQFalse, SQFalse); - sq_pop(vm, 1); + PushDocumentationRegisterFunction( "RegisterHookHelp" ); + sq_pushstring(vm, name, -1); + sq_pushstring(vm, signature, -1); + sq_pushstring(vm, pFuncDesc.m_pszDescription ? pFuncDesc.m_pszDescription : "", -1); + CallDocumentationRegisterFunction( 3 ); } void RegisterMemberDocumentation(HSQUIRRELVM vm, const ScriptMemberDesc_t& pDesc, ScriptClassDesc_t* pClassDesc = nullptr) @@ -1619,21 +1609,15 @@ void RegisterMemberDocumentation(HSQUIRRELVM vm, const ScriptMemberDesc_t& pDesc if (pDesc.m_pszScriptName) V_strcat_safe(name, pDesc.m_pszScriptName); - char signature[256] = ""; V_snprintf(signature, sizeof(signature), "%s %s", ScriptDataTypeToName(pDesc.m_ReturnType), name); - // RegisterHookHelp(name, signature, description) - sq_pushroottable(vm); - sq_pushstring(vm, "RegisterMemberHelp", -1); - sq_get(vm, -2); - sq_remove(vm, -2); - sq_pushroottable(vm); - sq_pushstring(vm, name, -1); - sq_pushstring(vm, signature, -1); - sq_pushstring(vm, pDesc.m_pszDescription ? pDesc.m_pszDescription : "", -1); - sq_call(vm, 4, SQFalse, SQFalse); - sq_pop(vm, 1); + // RegisterMemberHelp(name, signature, description) + PushDocumentationRegisterFunction( "RegisterMemberHelp" ); + sq_pushstring(vm, name, -1); + sq_pushstring(vm, signature, -1); + sq_pushstring(vm, pDesc.m_pszDescription ? pDesc.m_pszDescription : "", -1); + CallDocumentationRegisterFunction( 3 ); } @@ -2449,6 +2433,41 @@ bool SquirrelVM::SetValue(HSCRIPT hScope, const char* pszKey, const ScriptVarian return true; } +bool SquirrelVM::SetValue( HSCRIPT hScope, const ScriptVariant_t& key, const ScriptVariant_t& val ) +{ + SquirrelSafeCheck safeCheck(vm_); + HSQOBJECT obj = *(HSQOBJECT*)hScope; + if (hScope) + { + Assert(hScope != INVALID_HSCRIPT); + sq_pushobject(vm_, obj); + } + else + { + sq_pushroottable(vm_); + } + + if ( sq_isarray(obj) ) + { + Assert( key.m_type == FIELD_INTEGER ); + + sq_pushinteger(vm_, key.m_int); + PushVariant(vm_, val); + + sq_set(vm_, -3); + } + else + { + PushVariant(vm_, key); + PushVariant(vm_, val); + + sq_newslot(vm_, -3, SQFalse); + } + + sq_pop(vm_, 1); + return true; +} + void SquirrelVM::CreateTable(ScriptVariant_t& Table) { SquirrelSafeCheck safeCheck(vm_); @@ -2464,15 +2483,17 @@ void SquirrelVM::CreateTable(ScriptVariant_t& Table) Table = (HSCRIPT)obj; } +// +// input table/array/class/instance/string +// int SquirrelVM::GetNumTableEntries(HSCRIPT hScope) { SquirrelSafeCheck safeCheck(vm_); if (!hScope) { - // TODO: This is called hScope but seems like just a table so - // lets not fallback to root table - return 0; + // sq_getsize returns -1 on invalid input + return -1; } HSQOBJECT* scope = (HSQOBJECT*)hScope; @@ -2565,6 +2586,47 @@ bool SquirrelVM::GetValue(HSCRIPT hScope, const char* pszKey, ScriptVariant_t* p return true; } +bool SquirrelVM::GetValue( HSCRIPT hScope, ScriptVariant_t key, ScriptVariant_t* pValue ) +{ + SquirrelSafeCheck safeCheck(vm_); + + Assert(pValue); + if (!pValue) + { + return false; + } + + if (hScope) + { + HSQOBJECT* scope = (HSQOBJECT*)hScope; + Assert(hScope != INVALID_HSCRIPT); + sq_pushobject(vm_, *scope); + } + else + { + sq_pushroottable(vm_); + } + + PushVariant(vm_, key); + + if (sq_get(vm_, -2) != SQ_OK) + { + sq_pop(vm_, 1); + return false; + } + + if (!getVariant(vm_, -1, *pValue)) + { + sq_pop(vm_, 2); + return false; + } + + sq_pop(vm_, 2); + + return true; +} + + void SquirrelVM::ReleaseValue(ScriptVariant_t& value) { SquirrelSafeCheck safeCheck(vm_); @@ -2609,6 +2671,33 @@ bool SquirrelVM::ClearValue(HSCRIPT hScope, const char* pszKey) sq_pop(vm_, 1); return true; } + +bool SquirrelVM::ClearValue(HSCRIPT hScope, ScriptVariant_t pKey) +{ + SquirrelSafeCheck safeCheck(vm_); + + if (hScope) + { + HSQOBJECT* scope = (HSQOBJECT*)hScope; + Assert(hScope != INVALID_HSCRIPT); + sq_pushobject(vm_, *scope); + } + else + { + sq_pushroottable(vm_); + } + + PushVariant(vm_, pKey); + if (SQ_FAILED(sq_deleteslot(vm_, -2, SQFalse))) + { + sq_pop(vm_, 1); + return false; + } + + sq_pop(vm_, 1); + return true; +} + /* void SquirrelVM::CreateArray(ScriptVariant_t &arr, int size) { @@ -2629,9 +2718,11 @@ bool SquirrelVM::ArrayAppend(HSCRIPT hArray, const ScriptVariant_t &val) { SquirrelSafeCheck safeCheck(vm_); - HSQOBJECT *arr = (HSQOBJECT*)hArray; + HSQOBJECT arr = *(HSQOBJECT*)hArray; + if ( !sq_isarray(arr) ) + return false; - sq_pushobject(vm_, *arr); + sq_pushobject(vm_, arr); PushVariant(vm_, val); bool ret = sq_arrayappend(vm_, -2) == SQ_OK; sq_pop(vm_, 1); diff --git a/sp/src/vscript/vscript_squirrel.nut b/sp/src/vscript/vscript_squirrel.nut index f4d28227..cb929807 100644 --- a/sp/src/vscript/vscript_squirrel.nut +++ b/sp/src/vscript/vscript_squirrel.nut @@ -106,14 +106,16 @@ class CSimpleCallChainer chain = null; } -DocumentedFuncs <- {} -DocumentedClasses <- {} -DocumentedEnums <- {} -DocumentedConsts <- {} -DocumentedHooks <- {} -DocumentedMembers <- {} +__Documentation <- {} -function AddAliasedToTable(name, signature, description, table) +local DocumentedFuncs = {} +local DocumentedClasses = {} +local DocumentedEnums = {} +local DocumentedConsts = {} +local DocumentedHooks = {} +local DocumentedMembers = {} + +local function AddAliasedToTable(name, signature, description, table) { // This is an alias function, could use split() if we could guarantee // that ':' would not occur elsewhere in the description and Squirrel had @@ -129,7 +131,7 @@ function AddAliasedToTable(name, signature, description, table) table[name] <- [signature, description]; } -function RegisterHelp(name, signature, description) +function __Documentation::RegisterHelp(name, signature, description) { if (description.len() && description[0] == '#') { @@ -141,17 +143,17 @@ function RegisterHelp(name, signature, description) } } -function RegisterClassHelp(name, baseclass, description) +function __Documentation::RegisterClassHelp(name, baseclass, description) { DocumentedClasses[name] <- [baseclass, description]; } -function RegisterEnumHelp(name, num_elements, description) +function __Documentation::RegisterEnumHelp(name, num_elements, description) { DocumentedEnums[name] <- [num_elements, description]; } -function RegisterConstHelp(name, signature, description) +function __Documentation::RegisterConstHelp(name, signature, description) { if (description.len() && description[0] == '#') { @@ -163,31 +165,31 @@ function RegisterConstHelp(name, signature, description) } } -function RegisterHookHelp(name, signature, description) +function __Documentation::RegisterHookHelp(name, signature, description) { DocumentedHooks[name] <- [signature, description]; } -function RegisterMemberHelp(name, signature, description) +function __Documentation::RegisterMemberHelp(name, signature, description) { DocumentedMembers[name] <- [signature, description]; } -function printdoc( text ) +local function printdoc( text ) { return ::printc(200,224,255,text); } -function printdocl( text ) +local function printdocl( text ) { return printdoc(text + "\n"); } -function PrintClass(name, doc) +local function PrintClass(name, doc) { local text = "=====================================\n"; - text += ("Class: " + name + "\n"); - text += ("Base: " + doc[0] + "\n"); + text += ("Class: " + name + "\n"); + text += ("Base: " + doc[0] + "\n"); if (doc[1].len()) text += ("Description: " + doc[1] + "\n"); text += "=====================================\n\n"; @@ -195,7 +197,7 @@ function PrintClass(name, doc) printdoc(text); } -function PrintFunc(name, doc) +local function PrintFunc(name, doc) { local text = "Function: " + name + "\n" @@ -220,7 +222,7 @@ function PrintFunc(name, doc) printdocl(text); } -function PrintMember(name, doc) +local function PrintMember(name, doc) { local text = ("Member: " + name + "\n"); text += ("Signature: " + doc[0] + "\n"); @@ -229,11 +231,11 @@ function PrintMember(name, doc) printdocl(text); } -function PrintEnum(name, doc) +local function PrintEnum(name, doc) { local text = "=====================================\n"; - text += ("Enum: " + name + "\n"); - text += ("Elements: " + doc[0] + "\n"); + text += ("Enum: " + name + "\n"); + text += ("Elements: " + doc[0] + "\n"); if (doc[1].len()) text += ("Description: " + doc[1] + "\n"); text += "=====================================\n\n"; @@ -241,25 +243,25 @@ function PrintEnum(name, doc) printdoc(text); } -function PrintConst(name, doc) +local function PrintConst(name, doc) { local text = ("Constant: " + name + "\n"); if (doc[0] == null) { - text += ("Value: null\n"); + text += ("Value: null\n"); } else { - text += ("Value: " + doc[0] + "\n"); + text += ("Value: " + doc[0] + "\n"); } if (doc[1].len()) text += ("Description: " + doc[1] + "\n"); printdocl(text); } -function PrintHook(name, doc) +local function PrintHook(name, doc) { - local text = ("Hook: " + name + "\n"); + local text = ("Hook: " + name + "\n"); if (doc[0] == null) { // Is an aliased function @@ -281,15 +283,15 @@ function PrintHook(name, doc) printdocl(text); } -function PrintMatchesInDocList(pattern, list, printfunc) +local function PrintMatchesInDocList(pattern, list, printfunc) { - local foundMatches = false; + local foundMatches = 0; foreach(name, doc in list) { if (pattern == "*" || name.tolower().find(pattern) != null || (doc[1].len() && doc[1].tolower().find(pattern) != null)) { - foundMatches = true; + foundMatches = 1; printfunc(name, doc) } } @@ -297,40 +299,41 @@ function PrintMatchesInDocList(pattern, list, printfunc) return foundMatches; } -function PrintHelp(pattern = "*") +function __Documentation::PrintHelp(pattern = "*") { - local foundMatches = false; local patternLower = pattern.tolower(); // Have a specific order - foundMatches = ( PrintMatchesInDocList( patternLower, DocumentedEnums, PrintEnum ) || foundMatches ); - foundMatches = ( PrintMatchesInDocList( patternLower, DocumentedConsts, PrintConst ) || foundMatches ); - foundMatches = ( PrintMatchesInDocList( patternLower, DocumentedClasses, PrintClass ) || foundMatches ); - foundMatches = ( PrintMatchesInDocList( patternLower, DocumentedFuncs, PrintFunc ) || foundMatches ); - foundMatches = ( PrintMatchesInDocList( patternLower, DocumentedMembers, PrintMember ) || foundMatches ); - foundMatches = ( PrintMatchesInDocList( patternLower, DocumentedHooks, PrintHook ) || foundMatches ); - - if (!foundMatches) + if (!( + PrintMatchesInDocList( patternLower, DocumentedEnums, PrintEnum ) | + PrintMatchesInDocList( patternLower, DocumentedConsts, PrintConst ) | + PrintMatchesInDocList( patternLower, DocumentedClasses, PrintClass ) | + PrintMatchesInDocList( patternLower, DocumentedFuncs, PrintFunc ) | + PrintMatchesInDocList( patternLower, DocumentedMembers, PrintMember ) | + PrintMatchesInDocList( patternLower, DocumentedHooks, PrintHook ) + )) + { printdocl("Pattern " + pattern + " not found"); + } } // Vector documentation -RegisterClassHelp( "Vector", "", "Basic 3-float Vector class." ); -RegisterHelp( "Vector::Length", "float Vector::Length()", "Return the vector's length." ); -RegisterHelp( "Vector::LengthSqr", "float Vector::LengthSqr()", "Return the vector's squared length." ); -RegisterHelp( "Vector::Length2D", "float Vector::Length2D()", "Return the vector's 2D length." ); -RegisterHelp( "Vector::Length2DSqr", "float Vector::Length2DSqr()", "Return the vector's squared 2D length." ); +__Documentation.RegisterClassHelp( "Vector", "", "Basic 3-float Vector class." ); +__Documentation.RegisterHelp( "Vector::Length", "float Vector::Length()", "Return the vector's length." ); +__Documentation.RegisterHelp( "Vector::LengthSqr", "float Vector::LengthSqr()", "Return the vector's squared length." ); +__Documentation.RegisterHelp( "Vector::Length2D", "float Vector::Length2D()", "Return the vector's 2D length." ); +__Documentation.RegisterHelp( "Vector::Length2DSqr", "float Vector::Length2DSqr()", "Return the vector's squared 2D length." ); -RegisterHelp( "Vector::Normalized", "float Vector::Normalized()", "Return a normalized version of the vector." ); -RegisterHelp( "Vector::Norm", "void Vector::Norm()", "Normalize the vector in place." ); -RegisterHelp( "Vector::Scale", "vector Vector::Scale(float)", "Scale the vector's magnitude and return the result." ); -RegisterHelp( "Vector::Dot", "float Vector::Dot(vector)", "Return the dot/scalar product of two vectors." ); -RegisterHelp( "Vector::Cross", "float Vector::Cross(vector)", "Return the vector product of two vectors." ); +__Documentation.RegisterHelp( "Vector::Normalized", "float Vector::Normalized()", "Return a normalized version of the vector." ); +__Documentation.RegisterHelp( "Vector::Norm", "void Vector::Norm()", "Normalize the vector in place." ); +__Documentation.RegisterHelp( "Vector::Scale", "vector Vector::Scale(float)", "Scale the vector's magnitude and return the result." ); +__Documentation.RegisterHelp( "Vector::Dot", "float Vector::Dot(vector)", "Return the dot/scalar product of two vectors." ); +__Documentation.RegisterHelp( "Vector::Cross", "float Vector::Cross(vector)", "Return the vector product of two vectors." ); -RegisterHelp( "Vector::ToKVString", "string Vector::ToKVString()", "Return a vector as a string in KeyValue form, without separation commas." ); +__Documentation.RegisterHelp( "Vector::ToKVString", "string Vector::ToKVString()", "Return a vector as a string in KeyValue form, without separation commas." ); -RegisterMemberHelp( "Vector.x", "float Vector.x", "The vector's X coordinate on the cartesian X axis." ); -RegisterMemberHelp( "Vector.y", "float Vector.y", "The vector's Y coordinate on the cartesian Y axis." ); -RegisterMemberHelp( "Vector.z", "float Vector.z", "The vector's Z coordinate on the cartesian Z axis." ); +__Documentation.RegisterMemberHelp( "Vector.x", "float Vector.x", "The vector's X coordinate on the cartesian X axis." ); +__Documentation.RegisterMemberHelp( "Vector.y", "float Vector.y", "The vector's Y coordinate on the cartesian Y axis." ); +__Documentation.RegisterMemberHelp( "Vector.z", "float Vector.z", "The vector's Z coordinate on the cartesian Z axis." ); )vscript"; \ No newline at end of file