@@ -2190,7 +2190,7 @@ BEGIN_DATADESC_NO_BASE( CBaseEntity )
2190
2190
DEFINE_THINKFUNC( ShadowCastDistThink ),
2191
2191
DEFINE_THINKFUNC( ScriptThink ),
2192
2192
#ifdef MAPBASE_VSCRIPT
2193
- DEFINE_THINKFUNC ( ScriptThinkH ),
2193
+ DEFINE_THINKFUNC ( ScriptContextThink ),
2194
2194
#endif
2195
2195
2196
2196
#ifdef MAPBASE
@@ -2442,6 +2442,7 @@ BEGIN_ENT_SCRIPTDESC_ROOT( CBaseEntity, "Root class of all server-side entities"
2442
2442
#ifdef MAPBASE_VSCRIPT
2443
2443
DEFINE_SCRIPTFUNC_NAMED ( ScriptSetThinkFunction, " SetThinkFunction" , " " )
2444
2444
DEFINE_SCRIPTFUNC_NAMED( ScriptStopThinkFunction, " StopThinkFunction" , " " )
2445
+ DEFINE_SCRIPTFUNC_NAMED( ScriptSetContextThink, " SetContextThink" , " Set a think function on this entity." )
2445
2446
DEFINE_SCRIPTFUNC_NAMED( ScriptSetThink, " SetThink" , " " )
2446
2447
DEFINE_SCRIPTFUNC_NAMED( ScriptStopThink, " StopThink" , " " )
2447
2448
@@ -2590,11 +2591,12 @@ void CBaseEntity::UpdateOnRemove( void )
2590
2591
m_hScriptInstance = NULL ;
2591
2592
2592
2593
#ifdef MAPBASE_VSCRIPT
2593
- if ( m_hfnThink )
2594
+ FOR_EACH_VEC ( m_ScriptThinkFuncs, i )
2594
2595
{
2595
- g_pScriptVM-> ReleaseScript ( m_hfnThink ) ;
2596
- m_hfnThink = NULL ;
2596
+ HSCRIPT h = m_ScriptThinkFuncs[i]. m_hfnThink ;
2597
+ if ( h ) g_pScriptVM-> ReleaseScript ( h ) ;
2597
2598
}
2599
+ m_ScriptThinkFuncs.Purge ();
2598
2600
#endif // MAPBASE_VSCRIPT
2599
2601
}
2600
2602
}
@@ -8653,60 +8655,172 @@ void CBaseEntity::ScriptStopThinkFunction()
8653
8655
SetContextThink ( NULL , TICK_NEVER_THINK, " ScriptThink" );
8654
8656
}
8655
8657
8658
+
8659
+ static inline void ScriptStopContextThink ( scriptthinkfunc_t *context )
8660
+ {
8661
+ g_pScriptVM->ReleaseScript ( context->m_hfnThink );
8662
+ context->m_hfnThink = NULL ;
8663
+ context->m_nNextThinkTick = TICK_NEVER_THINK;
8664
+ }
8665
+
8656
8666
// -----------------------------------------------------------------------------
8667
+ //
8657
8668
// -----------------------------------------------------------------------------
8658
- void CBaseEntity::ScriptThinkH ()
8669
+ void CBaseEntity::ScriptContextThink ()
8659
8670
{
8660
- ScriptVariant_t varThinkRetVal;
8661
- if ( g_pScriptVM->ExecuteFunction (m_hfnThink, NULL , 0 , &varThinkRetVal, NULL , true ) == SCRIPT_ERROR )
8671
+ float flNextThink = FLT_MAX;
8672
+ int nScheduledTick = 0 ;
8673
+
8674
+ for ( int i = m_ScriptThinkFuncs.Count (); i--; )
8662
8675
{
8663
- DevWarning (" %s FAILED to call script think function (invalid closure)!\n " , GetDebugName ());
8664
- ScriptStopThink ();
8665
- return ;
8676
+ scriptthinkfunc_t *cur = &m_ScriptThinkFuncs[i];
8677
+
8678
+ if ( cur->m_nNextThinkTick == TICK_NEVER_THINK )
8679
+ continue ;
8680
+
8681
+ if ( cur->m_nNextThinkTick > gpGlobals->tickcount )
8682
+ {
8683
+ // There is more to execute, don't stop thinking if the rest are done.
8684
+
8685
+ // also find the shortest schedule
8686
+ if ( !nScheduledTick || nScheduledTick > cur->m_nNextThinkTick )
8687
+ {
8688
+ nScheduledTick = cur->m_nNextThinkTick ;
8689
+ }
8690
+ continue ;
8691
+ }
8692
+
8693
+ ScriptVariant_t varReturn;
8694
+
8695
+ if ( cur->m_bNoParam )
8696
+ {
8697
+ if ( g_pScriptVM->Call ( cur->m_hfnThink , NULL , true , &varReturn ) == SCRIPT_ERROR )
8698
+ {
8699
+ ScriptStopContextThink (cur);
8700
+ m_ScriptThinkFuncs.Remove (i);
8701
+ continue ;
8702
+ }
8703
+ }
8704
+ else
8705
+ {
8706
+ if ( g_pScriptVM->Call ( cur->m_hfnThink , NULL , true , &varReturn, m_hScriptInstance ) == SCRIPT_ERROR )
8707
+ {
8708
+ ScriptStopContextThink (cur);
8709
+ m_ScriptThinkFuncs.Remove (i);
8710
+ continue ;
8711
+ }
8712
+ }
8713
+
8714
+ float flReturn;
8715
+ if ( !varReturn.AssignTo ( &flReturn ) )
8716
+ {
8717
+ ScriptStopContextThink (cur);
8718
+ m_ScriptThinkFuncs.Remove (i);
8719
+ continue ;
8720
+ }
8721
+
8722
+ if ( flReturn < 0 .0f )
8723
+ {
8724
+ ScriptStopContextThink (cur);
8725
+ m_ScriptThinkFuncs.Remove (i);
8726
+ continue ;
8727
+ }
8728
+
8729
+ // find the shortest delay
8730
+ if ( flReturn < flNextThink )
8731
+ {
8732
+ flNextThink = flReturn;
8733
+ }
8734
+
8735
+ cur->m_nNextThinkTick = TIME_TO_TICKS ( gpGlobals->curtime + flReturn );
8666
8736
}
8667
8737
8668
- float flThinkFrequency = 0 .f ;
8669
- if ( !varThinkRetVal.AssignTo (&flThinkFrequency) )
8738
+ if ( flNextThink < FLT_MAX )
8670
8739
{
8671
- // no return value stops thinking
8672
- ScriptStopThink ();
8673
- return ;
8740
+ SetNextThink ( gpGlobals->curtime + flNextThink, " ScriptContextThink" );
8741
+ }
8742
+ else if ( nScheduledTick )
8743
+ {
8744
+ SetNextThink ( TICKS_TO_TIME ( nScheduledTick ), " ScriptContextThink" );
8745
+ }
8746
+ else
8747
+ {
8748
+ SetNextThink ( TICK_NEVER_THINK, " ScriptContextThink" );
8674
8749
}
8675
-
8676
- SetNextThink ( gpGlobals->curtime + flThinkFrequency, " ScriptThinkH" );
8677
8750
}
8678
8751
8679
- void CBaseEntity::ScriptSetThink ( HSCRIPT hFunc, float flTime )
8752
+ // see ScriptSetThink
8753
+ static bool s_bScriptContextThinkNoParam = false ;
8754
+
8755
+ // -----------------------------------------------------------------------------
8756
+ //
8757
+ // -----------------------------------------------------------------------------
8758
+ void CBaseEntity::ScriptSetContextThink ( const char * szContext, HSCRIPT hFunc, float flTime )
8680
8759
{
8681
- if ( hFunc )
8760
+ scriptthinkfunc_t th;
8761
+ V_memset ( &th, 0x0 , sizeof (scriptthinkfunc_t ) );
8762
+ unsigned short hash = ( szContext && *szContext ) ? HashString ( szContext ) : 0 ;
8763
+ bool bFound = false ;
8764
+
8765
+ FOR_EACH_VEC ( m_ScriptThinkFuncs, i )
8682
8766
{
8683
- if ( m_hfnThink )
8767
+ scriptthinkfunc_t f = m_ScriptThinkFuncs[i];
8768
+ if ( hash == f.m_iContextHash )
8684
8769
{
8685
- // release old func
8686
- ScriptStopThink ();
8770
+ th = f;
8771
+ m_ScriptThinkFuncs.Remove (i); // reorder
8772
+ bFound = true ;
8773
+ break ;
8687
8774
}
8775
+ }
8688
8776
8689
- // no type check here, print error on call instead
8690
- m_hfnThink = hFunc;
8777
+ if ( hFunc )
8778
+ {
8779
+ float nextthink = gpGlobals->curtime + flTime;
8691
8780
8692
- flTime = max ( 0 , flTime );
8693
- SetContextThink ( &CBaseEntity::ScriptThinkH, gpGlobals->curtime + flTime, " ScriptThinkH" );
8781
+ th.m_bNoParam = s_bScriptContextThinkNoParam;
8782
+ th.m_hfnThink = hFunc;
8783
+ th.m_iContextHash = hash;
8784
+ th.m_nNextThinkTick = TIME_TO_TICKS ( nextthink );
8785
+
8786
+ m_ScriptThinkFuncs.AddToHead ( th );
8787
+
8788
+ int nexttick = GetNextThinkTick ( RegisterThinkContext ( " ScriptContextThink" ) );
8789
+
8790
+ // sooner than next think
8791
+ if ( nexttick <= 0 || nexttick > th.m_nNextThinkTick )
8792
+ {
8793
+ SetContextThink ( &CBaseEntity::ScriptContextThink, nextthink, " ScriptContextThink" );
8794
+ }
8694
8795
}
8695
- else
8796
+ // null func input, think exists
8797
+ else if ( bFound )
8696
8798
{
8697
- ScriptStopThink ( );
8799
+ ScriptStopContextThink ( &th );
8698
8800
}
8699
8801
}
8700
8802
8803
+ // -----------------------------------------------------------------------------
8804
+ // m_bNoParam and s_bScriptContextThinkNoParam exist only to keep backwards compatibility
8805
+ // and are an alternative to this script closure:
8806
+ //
8807
+ // function CBaseEntity::SetThink( func, time )
8808
+ // {
8809
+ // SetContextThink( "", function(_){ return func() }, time )
8810
+ // }
8811
+ // -----------------------------------------------------------------------------
8812
+ void CBaseEntity::ScriptSetThink ( HSCRIPT hFunc, float time )
8813
+ {
8814
+ s_bScriptContextThinkNoParam = true ;
8815
+ ScriptSetContextThink ( NULL , hFunc, time );
8816
+ s_bScriptContextThinkNoParam = false ;
8817
+ }
8818
+
8701
8819
void CBaseEntity::ScriptStopThink ()
8702
8820
{
8703
- if (m_hfnThink)
8704
- {
8705
- g_pScriptVM->ReleaseScript (m_hfnThink);
8706
- m_hfnThink = NULL ;
8707
- }
8708
- SetContextThink ( NULL , TICK_NEVER_THINK, " ScriptThinkH" );
8821
+ ScriptSetContextThink ( NULL , NULL , 0 .0f );
8709
8822
}
8823
+
8710
8824
#endif // MAPBASE_VSCRIPT
8711
8825
8712
8826
// -----------------------------------------------------------------------------
0 commit comments