Fix ScriptContextThink precision errors

This commit is contained in:
samisalreadytaken 2021-04-18 18:43:05 +02:00
parent 6ed8b31091
commit d7a06e863e
3 changed files with 80 additions and 102 deletions

View File

@ -164,10 +164,9 @@ struct thinkfunc_t
#ifdef MAPBASE_VSCRIPT #ifdef MAPBASE_VSCRIPT
struct scriptthinkfunc_t struct scriptthinkfunc_t
{ {
int m_nNextThinkTick; float m_flNextThink;
HSCRIPT m_hfnThink; HSCRIPT m_hfnThink;
unsigned short m_iContextHash; unsigned m_iContextHash;
bool m_bNoParam;
}; };
#endif #endif
@ -295,6 +294,8 @@ public:
string_t m_iszScriptId; string_t m_iszScriptId;
#ifdef MAPBASE_VSCRIPT #ifdef MAPBASE_VSCRIPT
CScriptScope m_ScriptScope; CScriptScope m_ScriptScope;
static ScriptHook_t g_Hook_UpdateOnRemove;
#endif #endif
// IClientUnknown overrides. // IClientUnknown overrides.

View File

@ -341,9 +341,9 @@ struct thinkfunc_t
#ifdef MAPBASE_VSCRIPT #ifdef MAPBASE_VSCRIPT
struct scriptthinkfunc_t struct scriptthinkfunc_t
{ {
int m_nNextThinkTick; float m_flNextThink;
HSCRIPT m_hfnThink; HSCRIPT m_hfnThink;
unsigned short m_iContextHash; unsigned m_iContextHash;
bool m_bNoParam; bool m_bNoParam;
}; };
#endif #endif
@ -2115,6 +2115,9 @@ public:
int ScriptGetMoveType() { return GetMoveType(); } int ScriptGetMoveType() { return GetMoveType(); }
void ScriptSetMoveType( int iMoveType ) { SetMoveType( (MoveType_t)iMoveType ); } void ScriptSetMoveType( int iMoveType ) { SetMoveType( (MoveType_t)iMoveType ); }
int ScriptGetSolid() { return GetSolid(); }
void ScriptSetSolid( int i ) { SetSolid( (SolidType_t)i ); }
bool ScriptDispatchInteraction( int interactionType, HSCRIPT data, HSCRIPT sourceEnt ); bool ScriptDispatchInteraction( int interactionType, HSCRIPT data, HSCRIPT sourceEnt );
int ScriptGetTakeDamage() { return m_takedamage; } int ScriptGetTakeDamage() { return m_takedamage; }

View File

@ -2713,13 +2713,20 @@ HSCRIPT CBaseEntity::ScriptGetPhysicsObject( void )
return NULL; return NULL;
} }
#ifdef GAME_DLL
#define SCRIPT_NEVER_THINK TICK_NEVER_THINK
#else
#define SCRIPT_NEVER_THINK CLIENT_THINK_NEVER
#endif
static inline void ScriptStopContextThink( scriptthinkfunc_t *context ) static inline void ScriptStopContextThink( scriptthinkfunc_t *context )
{ {
Assert( context->m_hfnThink ); Assert( context->m_hfnThink );
Assert( context->m_flNextThink == SCRIPT_NEVER_THINK );
g_pScriptVM->ReleaseScript( context->m_hfnThink ); g_pScriptVM->ReleaseScript( context->m_hfnThink );
context->m_hfnThink = NULL; context->m_hfnThink = NULL;
//context->m_nNextThinkTick = TICK_NEVER_THINK;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -2728,55 +2735,56 @@ static inline void ScriptStopContextThink( scriptthinkfunc_t *context )
void CBaseEntity::ScriptContextThink() void CBaseEntity::ScriptContextThink()
{ {
float flNextThink = FLT_MAX; float flNextThink = FLT_MAX;
int nScheduledTick = 0; float flScheduled = 0.0f;
for ( int i = 0; i < m_ScriptThinkFuncs.Count(); ++i ) for ( int i = 0; i < m_ScriptThinkFuncs.Count(); ++i )
{ {
scriptthinkfunc_t *cur = m_ScriptThinkFuncs[i]; scriptthinkfunc_t *cur = m_ScriptThinkFuncs[i];
if ( cur->m_nNextThinkTick == TICK_NEVER_THINK ) if ( cur->m_flNextThink == SCRIPT_NEVER_THINK )
{ {
continue; continue;
} }
if ( cur->m_nNextThinkTick > gpGlobals->tickcount ) if ( cur->m_flNextThink > gpGlobals->curtime )
{ {
// There is more to execute, don't stop thinking if the rest are done. if ( ( flScheduled == 0.0f ) || ( flScheduled > cur->m_flNextThink ) )
// Find the shortest schedule
if ( !nScheduledTick || nScheduledTick > cur->m_nNextThinkTick )
{ {
nScheduledTick = cur->m_nNextThinkTick; flScheduled = cur->m_flNextThink;
} }
continue; continue;
} }
#ifdef _DEBUG #ifdef _DEBUG
// going to run the script func // going to run the script func
cur->m_nNextThinkTick = 0; cur->m_flNextThink = 0;
#endif #endif
ScriptVariant_t varReturn; ScriptVariant_t varReturn;
#ifndef CLIENT_DLL
if ( !cur->m_bNoParam ) if ( !cur->m_bNoParam )
{ {
#endif
ScriptVariant_t arg = m_hScriptInstance; ScriptVariant_t arg = m_hScriptInstance;
if ( g_pScriptVM->ExecuteFunction( cur->m_hfnThink, &arg, 1, &varReturn, NULL, true ) == SCRIPT_ERROR ) if ( g_pScriptVM->ExecuteFunction( cur->m_hfnThink, &arg, 1, &varReturn, NULL, true ) == SCRIPT_ERROR )
{ {
cur->m_nNextThinkTick = TICK_NEVER_THINK; cur->m_flNextThink = SCRIPT_NEVER_THINK;
continue; continue;
} }
#ifndef CLIENT_DLL
} }
else else
{ {
if ( g_pScriptVM->ExecuteFunction( cur->m_hfnThink, NULL, 0, &varReturn, NULL, true ) == SCRIPT_ERROR ) if ( g_pScriptVM->ExecuteFunction( cur->m_hfnThink, NULL, 0, &varReturn, NULL, true ) == SCRIPT_ERROR )
{ {
cur->m_nNextThinkTick = TICK_NEVER_THINK; cur->m_flNextThink = SCRIPT_NEVER_THINK;
continue; continue;
} }
} }
#endif
if ( cur->m_nNextThinkTick == TICK_NEVER_THINK ) if ( cur->m_flNextThink == SCRIPT_NEVER_THINK )
{ {
// stopped from script while thinking // stopped from script while thinking
continue; continue;
@ -2785,13 +2793,13 @@ void CBaseEntity::ScriptContextThink()
float flReturn; float flReturn;
if ( !varReturn.AssignTo( &flReturn ) ) if ( !varReturn.AssignTo( &flReturn ) )
{ {
cur->m_nNextThinkTick = TICK_NEVER_THINK; cur->m_flNextThink = SCRIPT_NEVER_THINK;
continue; continue;
} }
if ( flReturn < 0.0f ) if ( flReturn < 0.0f )
{ {
cur->m_nNextThinkTick = TICK_NEVER_THINK; cur->m_flNextThink = SCRIPT_NEVER_THINK;
continue; continue;
} }
@ -2800,96 +2808,61 @@ void CBaseEntity::ScriptContextThink()
flNextThink = flReturn; flNextThink = flReturn;
} }
cur->m_nNextThinkTick = TIME_TO_TICKS( gpGlobals->curtime + flReturn ); cur->m_flNextThink = gpGlobals->curtime + flReturn - 0.001;
} }
// deferred safe removal // deferred safe removal
for ( int i = 0; i < m_ScriptThinkFuncs.Count(); ) for ( int i = 0; i < m_ScriptThinkFuncs.Count(); )
{ {
if ( m_ScriptThinkFuncs[i]->m_nNextThinkTick == TICK_NEVER_THINK ) scriptthinkfunc_t *cur = m_ScriptThinkFuncs[i];
if ( cur->m_flNextThink == SCRIPT_NEVER_THINK )
{ {
ScriptStopContextThink( m_ScriptThinkFuncs[i] ); ScriptStopContextThink( cur );
delete m_ScriptThinkFuncs[i]; delete cur;
m_ScriptThinkFuncs.Remove(i); m_ScriptThinkFuncs.Remove(i);
} }
else ++i; else ++i;
} }
bool bNewNext = flNextThink < FLT_MAX; if ( flNextThink < FLT_MAX )
#ifdef _DEBUG
#ifdef GAME_DLL
int nNextThinkTick = GetNextThinkTick("ScriptContextThink"); // -1
#else
int nNextThinkTick = GetNextThinkTick(); // 0
#endif
if ( ( nNextThinkTick <= 0 ) || ( nNextThinkTick >= nScheduledTick ) || ( nNextThinkTick == gpGlobals->tickcount ) )
{ {
#endif if ( flScheduled > 0.0f )
if ( nScheduledTick )
{ {
float flScheduledTime = TICKS_TO_TIME( nScheduledTick ); flNextThink = min( gpGlobals->curtime + flNextThink, flScheduled );
if ( bNewNext )
{
flNextThink = min( gpGlobals->curtime + flNextThink, flScheduledTime );
} }
else else
{
flNextThink = flScheduledTime;
}
}
else
{
if ( bNewNext )
{ {
flNextThink = gpGlobals->curtime + flNextThink; flNextThink = gpGlobals->curtime + flNextThink;
} }
}
else else
{ {
#ifdef GAME_DLL if ( flScheduled > 0.0f )
flNextThink = TICK_NEVER_THINK; {
#else flNextThink = flScheduled;
flNextThink = CLIENT_THINK_NEVER; }
#endif else
{
flNextThink = SCRIPT_NEVER_THINK;
} }
} }
#ifdef _DEBUG #ifdef _DEBUG
} #ifdef GAME_DLL
else int nNextThinkTick = GetNextThinkTick("ScriptContextThink");
float flNextThinkTime = TICKS_TO_TIME(nNextThinkTick);
// If internal next think tick is earlier than what we have here with flNextThink,
// whoever set that think may fail. In worst case scenario the entity may stop thinking.
if ( nNextThinkTick > gpGlobals->tickcount )
{ {
// Next think was set (from script) to a sooner tick while thinking? if ( flNextThink == SCRIPT_NEVER_THINK )
Assert(0);
if ( flNextThinkTime < flNextThink )
Assert(0); Assert(0);
if ( nScheduledTick )
{
int nNextSchedule = min( nScheduledTick, nNextThinkTick );
float flNextSchedule = TICKS_TO_TIME( nNextSchedule );
if ( bNewNext )
{
flNextThink = min( gpGlobals->curtime + flNextThink, flNextSchedule );
}
else
{
flNextThink = flNextSchedule;
}
}
else
{
float nextthink = TICKS_TO_TIME( nNextThinkTick );
if ( bNewNext )
{
flNextThink = min( gpGlobals->curtime + flNextThink, nextthink );
}
else
{
flNextThink = nextthink;
}
}
} }
#endif #endif
#endif
#ifdef GAME_DLL #ifdef GAME_DLL
SetNextThink( flNextThink, "ScriptContextThink" ); SetNextThink( flNextThink, "ScriptContextThink" );
@ -2898,8 +2871,10 @@ void CBaseEntity::ScriptContextThink()
#endif #endif
} }
#ifndef CLIENT_DLL
// see ScriptSetThink // see ScriptSetThink
static bool s_bScriptContextThinkNoParam = false; static bool s_bScriptContextThinkNoParam = false;
#endif
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// //
@ -2917,7 +2892,7 @@ void CBaseEntity::ScriptSetContextThink( const char* szContext, HSCRIPT hFunc, f
#endif #endif
scriptthinkfunc_t *pf = NULL; scriptthinkfunc_t *pf = NULL;
unsigned short hash = ( szContext && *szContext ) ? HashString( szContext ) : 0; unsigned hash = szContext ? HashString( szContext ) : 0;
FOR_EACH_VEC( m_ScriptThinkFuncs, i ) FOR_EACH_VEC( m_ScriptThinkFuncs, i )
{ {
@ -2939,14 +2914,16 @@ void CBaseEntity::ScriptSetContextThink( const char* szContext, HSCRIPT hFunc, f
m_ScriptThinkFuncs.SetGrowSize(1); m_ScriptThinkFuncs.SetGrowSize(1);
m_ScriptThinkFuncs.AddToTail( pf ); m_ScriptThinkFuncs.AddToTail( pf );
pf->m_bNoParam = s_bScriptContextThinkNoParam;
pf->m_iContextHash = hash; pf->m_iContextHash = hash;
#ifndef CLIENT_DLL
pf->m_bNoParam = s_bScriptContextThinkNoParam;
#endif
} }
// update existing // update existing
else else
{ {
#ifdef _DEBUG #ifdef _DEBUG
if ( pf->m_nNextThinkTick == 0 ) if ( pf->m_flNextThink == 0 )
{ {
Warning("Script think ('%s') was changed while it was thinking!\n", szContext); Warning("Script think ('%s') was changed while it was thinking!\n", szContext);
} }
@ -2957,31 +2934,29 @@ void CBaseEntity::ScriptSetContextThink( const char* szContext, HSCRIPT hFunc, f
float nextthink = gpGlobals->curtime + flTime; float nextthink = gpGlobals->curtime + flTime;
pf->m_hfnThink = hFunc; pf->m_hfnThink = hFunc;
pf->m_nNextThinkTick = TIME_TO_TICKS( nextthink ); pf->m_flNextThink = nextthink;
#ifdef GAME_DLL #ifdef GAME_DLL
int nexttick = GetNextThinkTick( RegisterThinkContext( "ScriptContextThink" ) ); int nexttick = GetNextThinkTick( RegisterThinkContext( "ScriptContextThink" ) );
#else if ( nexttick <= 0 || TICKS_TO_TIME(nexttick) > nextthink )
int nexttick = GetNextThinkTick();
#endif
// sooner than next think
if ( nexttick <= 0 || nexttick > pf->m_nNextThinkTick )
{ {
#ifdef GAME_DLL
SetContextThink( &CBaseEntity::ScriptContextThink, nextthink, "ScriptContextThink" ); SetContextThink( &CBaseEntity::ScriptContextThink, nextthink, "ScriptContextThink" );
#else
SetNextClientThink( nextthink );
#endif
} }
#else
{
// let it self adjust
SetNextClientThink( gpGlobals->curtime );
}
#endif
} }
// null func input, think exists // null func input, think exists
else if ( pf ) else if ( pf )
{ {
pf->m_nNextThinkTick = TICK_NEVER_THINK; pf->m_flNextThink = SCRIPT_NEVER_THINK;
} }
} }
#ifndef CLIENT_DLL
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// m_bNoParam and s_bScriptContextThinkNoParam exist only to keep backwards compatibility // m_bNoParam and s_bScriptContextThinkNoParam exist only to keep backwards compatibility
// and are an alternative to this script closure: // and are an alternative to this script closure:
@ -2991,7 +2966,6 @@ void CBaseEntity::ScriptSetContextThink( const char* szContext, HSCRIPT hFunc, f
// SetContextThink( "", function(_){ return func() }, time ) // SetContextThink( "", function(_){ return func() }, time )
// } // }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#ifndef CLIENT_DLL
void CBaseEntity::ScriptSetThink( HSCRIPT hFunc, float time ) void CBaseEntity::ScriptSetThink( HSCRIPT hFunc, float time )
{ {
s_bScriptContextThinkNoParam = true; s_bScriptContextThinkNoParam = true;