forked from 0ad/0ad
Added support for cancelling a timeout or interval set using setTimeout/setInterval, which is used by the infidelity aura.
This was SVN commit r3272.
This commit is contained in:
parent
8f5b5b7b73
commit
5e0e3c32f3
@ -264,9 +264,10 @@ JSBool RemoveGlobalHandler( JSContext* cx, JSObject* UNUSED(obj), uint argc, jsv
|
||||
// The called function or script executes in the same scope as the
|
||||
// code that called setTimeout (amongst other things, the
|
||||
// 'this' reference is usually maintained)
|
||||
JSBool setTimeout( JSContext* cx, JSObject*, uint argc, jsval* argv, jsval* UNUSED(rval) )
|
||||
JSBool setTimeout( JSContext* cx, JSObject* obj, uint argc, jsval* argv, jsval* rval )
|
||||
{
|
||||
REQUIRE_PARAMS(2, setTimeout);
|
||||
REQUIRE_MIN_PARAMS(2, setTimeout);
|
||||
REQUIRE_MAX_PARAMS(3, setTimeout);
|
||||
|
||||
size_t delay;
|
||||
try
|
||||
@ -279,18 +280,35 @@ JSBool setTimeout( JSContext* cx, JSObject*, uint argc, jsval* argv, jsval* UNUS
|
||||
return( JS_TRUE );
|
||||
}
|
||||
|
||||
JSObject* scope;
|
||||
if( argc == 3 )
|
||||
{
|
||||
if( !JSVAL_IS_OBJECT( argv[2] ) )
|
||||
{
|
||||
JS_ReportError( cx, "Invalid timer parameters" );
|
||||
return( JS_TRUE );
|
||||
}
|
||||
scope = JSVAL_TO_OBJECT( argv[2] );
|
||||
}
|
||||
else
|
||||
{
|
||||
scope = JS_GetScopeChain( cx );
|
||||
}
|
||||
|
||||
switch( JS_TypeOfValue( cx, argv[0] ) )
|
||||
{
|
||||
case JSTYPE_STRING:
|
||||
{
|
||||
CStrW fragment = g_ScriptingHost.ValueToUCString( argv[0] );
|
||||
g_Scheduler.pushTime( delay, fragment, JS_GetScopeChain( cx ) );
|
||||
int id = g_Scheduler.pushTime( delay, fragment, scope );
|
||||
*rval = INT_TO_JSVAL( id );
|
||||
return( JS_TRUE );
|
||||
}
|
||||
case JSTYPE_FUNCTION:
|
||||
{
|
||||
JSFunction* fn = JS_ValueToFunction( cx, argv[0] );
|
||||
g_Scheduler.pushTime( delay, fn, JS_GetScopeChain( cx ) );
|
||||
int id = g_Scheduler.pushTime( delay, fn, scope );
|
||||
*rval = INT_TO_JSVAL( id );
|
||||
return( JS_TRUE );
|
||||
}
|
||||
default:
|
||||
@ -306,7 +324,7 @@ JSBool setTimeout( JSContext* cx, JSObject*, uint argc, jsval* argv, jsval* UNUS
|
||||
// returns:
|
||||
// notes:
|
||||
// - setTimeout's notes apply here as well.
|
||||
JSBool setInterval( JSContext* cx, JSObject*, uint argc, jsval* argv, jsval* UNUSED(rval) )
|
||||
JSBool setInterval( JSContext* cx, JSObject*, uint argc, jsval* argv, jsval* rval )
|
||||
{
|
||||
REQUIRE_MIN_PARAMS(2, setInterval);
|
||||
REQUIRE_MAX_PARAMS(3, setInterval);
|
||||
@ -337,13 +355,15 @@ JSBool setInterval( JSContext* cx, JSObject*, uint argc, jsval* argv, jsval* UNU
|
||||
case JSTYPE_STRING:
|
||||
{
|
||||
CStrW fragment = g_ScriptingHost.ValueToUCString( argv[0] );
|
||||
g_Scheduler.pushInterval( first, interval, fragment, JS_GetScopeChain( cx ) );
|
||||
int id = g_Scheduler.pushInterval( first, interval, fragment, JS_GetScopeChain( cx ) );
|
||||
*rval = INT_TO_JSVAL( id );
|
||||
return( JS_TRUE );
|
||||
}
|
||||
case JSTYPE_FUNCTION:
|
||||
{
|
||||
JSFunction* fn = JS_ValueToFunction( cx, argv[0] );
|
||||
g_Scheduler.pushInterval( first, interval, fn, JS_GetScopeChain( cx ) );
|
||||
int id = g_Scheduler.pushInterval( first, interval, fn, JS_GetScopeChain( cx ) );
|
||||
*rval = INT_TO_JSVAL( id );
|
||||
return( JS_TRUE );
|
||||
}
|
||||
default:
|
||||
@ -369,6 +389,33 @@ JSBool cancelInterval( JSContext* cx, JSObject*, uint argc, jsval* argv, jsval*
|
||||
}
|
||||
|
||||
|
||||
// Cause the scheduled task (timeout or interval) with the given ID to
|
||||
// no longer be called.
|
||||
// params:
|
||||
// returns:
|
||||
// notes:
|
||||
// - Execution continues until the end of the triggered function or
|
||||
// script fragment, but is not triggered again.
|
||||
JSBool cancelTimer( JSContext* cx, JSObject*, uint argc, jsval* argv, jsval* UNUSED(rval) )
|
||||
{
|
||||
REQUIRE_MIN_PARAMS(1, cancelTimer);
|
||||
REQUIRE_MAX_PARAMS(1, cancelTimer);
|
||||
|
||||
try
|
||||
{
|
||||
int id = ToPrimitive<int>( argv[0] );
|
||||
g_Scheduler.cancelTask( id );
|
||||
}
|
||||
catch( PSERROR_Scripting_ConversionFailed )
|
||||
{
|
||||
JS_ReportError( cx, "Invalid ID parameter" );
|
||||
return( JS_TRUE );
|
||||
}
|
||||
|
||||
return( JS_TRUE );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Game Setup
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -940,6 +987,7 @@ JSFunctionSpec ScriptFunctionTable[] =
|
||||
JS_FUNC(setTimeout, setTimeout, 2)
|
||||
JS_FUNC(setInterval, setInterval, 2)
|
||||
JS_FUNC(cancelInterval, cancelInterval, 0)
|
||||
JS_FUNC(cancelTimer, cancelTimer, 0)
|
||||
|
||||
// Game Setup
|
||||
JS_FUNC(startGame, startGame, 0)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -17,34 +17,49 @@ void CScheduler::pushFrame( size_t delay, const HEntity& destination, const CMes
|
||||
}
|
||||
*/
|
||||
|
||||
void CScheduler::pushTime( size_t delay, const CStrW& fragment, JSObject* operateOn )
|
||||
CScheduler::CScheduler()
|
||||
{
|
||||
timeScript.push( SDispatchObjectScript( fragment, simulationTime + delay, operateOn ) );
|
||||
m_nextTaskId = 1;
|
||||
}
|
||||
|
||||
void CScheduler::pushFrame( size_t delay, const CStrW& fragment, JSObject* operateOn )
|
||||
int CScheduler::pushTime( size_t delay, const CStrW& fragment, JSObject* operateOn )
|
||||
{
|
||||
frameScript.push( SDispatchObjectScript( fragment, frameCount + delay, operateOn ) );
|
||||
timeScript.push( SDispatchObjectScript( m_nextTaskId, fragment, simulationTime + delay, operateOn ) );
|
||||
return m_nextTaskId++;
|
||||
}
|
||||
|
||||
void CScheduler::pushInterval( size_t first, size_t interval, const CStrW& fragment, JSObject* operateOn )
|
||||
int CScheduler::pushFrame( size_t delay, const CStrW& fragment, JSObject* operateOn )
|
||||
{
|
||||
timeScript.push( SDispatchObjectScript( fragment, simulationTime + first, operateOn, interval ) );
|
||||
frameScript.push( SDispatchObjectScript( m_nextTaskId, fragment, frameCount + delay, operateOn ) );
|
||||
return m_nextTaskId++;
|
||||
}
|
||||
|
||||
void CScheduler::pushTime( size_t delay, JSFunction* script, JSObject* operateOn )
|
||||
int CScheduler::pushInterval( size_t first, size_t interval, const CStrW& fragment, JSObject* operateOn, int id )
|
||||
{
|
||||
timeFunction.push( SDispatchObjectFunction( script, simulationTime + delay, operateOn ) );
|
||||
if( !id )
|
||||
id = m_nextTaskId++;
|
||||
timeScript.push( SDispatchObjectScript( id, fragment, simulationTime + first, operateOn, interval ) );
|
||||
return id++;
|
||||
}
|
||||
|
||||
void CScheduler::pushFrame( size_t delay, JSFunction* script, JSObject* operateOn )
|
||||
int CScheduler::pushTime( size_t delay, JSFunction* script, JSObject* operateOn )
|
||||
{
|
||||
frameFunction.push( SDispatchObjectFunction( script, frameCount + delay, operateOn ) );
|
||||
timeFunction.push( SDispatchObjectFunction( m_nextTaskId, script, simulationTime + delay, operateOn ) );
|
||||
return m_nextTaskId++;
|
||||
}
|
||||
|
||||
void CScheduler::pushInterval( size_t first, size_t interval, JSFunction* function, JSObject* operateOn )
|
||||
int CScheduler::pushFrame( size_t delay, JSFunction* script, JSObject* operateOn )
|
||||
{
|
||||
timeFunction.push( SDispatchObjectFunction( function, simulationTime + first, operateOn, interval ) );
|
||||
frameFunction.push( SDispatchObjectFunction( m_nextTaskId, script, frameCount + delay, operateOn ) );
|
||||
return m_nextTaskId++;
|
||||
}
|
||||
|
||||
int CScheduler::pushInterval( size_t first, size_t interval, JSFunction* function, JSObject* operateOn, int id )
|
||||
{
|
||||
if( !id )
|
||||
id = m_nextTaskId++;
|
||||
timeFunction.push( SDispatchObjectFunction( id, function, simulationTime + first, operateOn, interval ) );
|
||||
return id++;
|
||||
}
|
||||
|
||||
void CScheduler::pushProgressTimer( CJSProgressTimer* progressTimer )
|
||||
@ -52,6 +67,11 @@ void CScheduler::pushProgressTimer( CJSProgressTimer* progressTimer )
|
||||
progressTimers.push_back( progressTimer );
|
||||
}
|
||||
|
||||
void CScheduler::cancelTask( int id )
|
||||
{
|
||||
tasksToCancel.insert( id );
|
||||
}
|
||||
|
||||
void CScheduler::update(size_t simElapsed)
|
||||
{
|
||||
simulationTime += simElapsed;
|
||||
@ -65,9 +85,16 @@ void CScheduler::update(size_t simElapsed)
|
||||
break;
|
||||
timeScript.pop();
|
||||
m_abortInterval = false;
|
||||
|
||||
if( tasksToCancel.find( top.id ) != tasksToCancel.end() )
|
||||
{
|
||||
tasksToCancel.erase( top.id );
|
||||
continue;
|
||||
}
|
||||
|
||||
g_ScriptingHost.ExecuteScript( top.script, CStrW( L"timer" ), top.operateOn );
|
||||
if( top.isRecurrent && !m_abortInterval )
|
||||
pushInterval( top.delay, top.delay, top.script, top.operateOn );
|
||||
pushInterval( top.delay, top.delay, top.script, top.operateOn, top.id );
|
||||
}
|
||||
while( !frameScript.empty() )
|
||||
{
|
||||
@ -75,6 +102,13 @@ void CScheduler::update(size_t simElapsed)
|
||||
if( top.deliveryTime > frameCount )
|
||||
break;
|
||||
frameScript.pop();
|
||||
|
||||
if( tasksToCancel.find( top.id ) != tasksToCancel.end() )
|
||||
{
|
||||
tasksToCancel.erase( top.id );
|
||||
continue;
|
||||
}
|
||||
|
||||
g_ScriptingHost.ExecuteScript( top.script, CStrW( L"timer" ), top.operateOn );
|
||||
}
|
||||
while( !timeFunction.empty() )
|
||||
@ -85,10 +119,16 @@ void CScheduler::update(size_t simElapsed)
|
||||
timeFunction.pop();
|
||||
m_abortInterval = false;
|
||||
|
||||
if( tasksToCancel.find( top.id ) != tasksToCancel.end() )
|
||||
{
|
||||
tasksToCancel.erase( top.id );
|
||||
continue;
|
||||
}
|
||||
|
||||
JS_CallFunction( g_ScriptingHost.getContext(), top.operateOn, top.function, 0, NULL, &rval );
|
||||
|
||||
if( top.isRecurrent && !m_abortInterval )
|
||||
pushInterval( top.delay, top.delay, top.function, top.operateOn );
|
||||
pushInterval( top.delay, top.delay, top.function, top.operateOn, top.id );
|
||||
}
|
||||
while( !frameFunction.empty() )
|
||||
{
|
||||
@ -97,6 +137,12 @@ void CScheduler::update(size_t simElapsed)
|
||||
break;
|
||||
frameFunction.pop();
|
||||
|
||||
if( tasksToCancel.find( top.id ) != tasksToCancel.end() )
|
||||
{
|
||||
tasksToCancel.erase( top.id );
|
||||
continue;
|
||||
}
|
||||
|
||||
JS_CallFunction( g_ScriptingHost.getContext(), top.operateOn, top.function, 0, NULL, &rval );
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include <queue>
|
||||
#include <list>
|
||||
#include <set>
|
||||
|
||||
#include "EntityMessage.h"
|
||||
#include "EntityHandles.h"
|
||||
@ -22,12 +23,13 @@ class CJSProgressTimer;
|
||||
// Message, destination and delivery time information.
|
||||
struct SDispatchObject
|
||||
{
|
||||
int id;
|
||||
size_t deliveryTime;
|
||||
bool isRecurrent; size_t delay;
|
||||
SDispatchObject( const size_t _deliveryTime )
|
||||
: deliveryTime( _deliveryTime ), isRecurrent( false ) {}
|
||||
SDispatchObject( const size_t _deliveryTime, const size_t _recurrence )
|
||||
: deliveryTime( _deliveryTime ), isRecurrent( true ), delay( _recurrence ) {}
|
||||
SDispatchObject( int _id, const size_t _deliveryTime )
|
||||
: id(_id), deliveryTime( _deliveryTime ), isRecurrent( false ) {}
|
||||
SDispatchObject( int _id, const size_t _deliveryTime, const size_t _recurrence )
|
||||
: id(_id), deliveryTime( _deliveryTime ), isRecurrent( true ), delay( _recurrence ) {}
|
||||
inline bool operator<( const SDispatchObject& compare ) const
|
||||
{
|
||||
return( deliveryTime > compare.deliveryTime );
|
||||
@ -38,20 +40,24 @@ struct SDispatchObjectScript : public SDispatchObject
|
||||
{
|
||||
CStrW script;
|
||||
JSObject* operateOn;
|
||||
inline SDispatchObjectScript( const CStrW& _script, const size_t _deliveryTime, JSObject* _operateOn = NULL )
|
||||
: SDispatchObject( _deliveryTime ), script( _script ), operateOn( _operateOn ) {}
|
||||
inline SDispatchObjectScript( const CStrW& _script, const size_t _deliveryTime, JSObject* _operateOn, const size_t recurrence )
|
||||
: SDispatchObject( _deliveryTime, recurrence ), script( _script ), operateOn( _operateOn ) {}
|
||||
inline SDispatchObjectScript( int _id, const CStrW& _script,
|
||||
const size_t _deliveryTime, JSObject* _operateOn = NULL )
|
||||
: SDispatchObject( _id, _deliveryTime ), script( _script ), operateOn( _operateOn ) {}
|
||||
inline SDispatchObjectScript( int _id, const CStrW& _script,
|
||||
const size_t _deliveryTime, JSObject* _operateOn, const size_t recurrence )
|
||||
: SDispatchObject( _id, _deliveryTime, recurrence ), script( _script ), operateOn( _operateOn ) {}
|
||||
};
|
||||
|
||||
struct SDispatchObjectFunction : public SDispatchObject
|
||||
{
|
||||
JSFunction* function;
|
||||
JSObject* operateOn;
|
||||
inline SDispatchObjectFunction( JSFunction* _function, const size_t _deliveryTime, JSObject* _operateOn = NULL )
|
||||
: SDispatchObject( _deliveryTime ), function( _function ), operateOn( _operateOn ) {}
|
||||
inline SDispatchObjectFunction( JSFunction* _function, const size_t _deliveryTime, JSObject* _operateOn, const size_t recurrence )
|
||||
: SDispatchObject( _deliveryTime, recurrence ), function( _function ), operateOn( _operateOn ) {}
|
||||
inline SDispatchObjectFunction( int _id, JSFunction* _function,
|
||||
const size_t _deliveryTime, JSObject* _operateOn = NULL )
|
||||
: SDispatchObject( _id, _deliveryTime ), function( _function ), operateOn( _operateOn ) {}
|
||||
inline SDispatchObjectFunction( int _id, JSFunction* _function,
|
||||
const size_t _deliveryTime, JSObject* _operateOn, const size_t recurrence )
|
||||
: SDispatchObject( _id, _deliveryTime, recurrence ), function( _function ), operateOn( _operateOn ) {}
|
||||
};
|
||||
|
||||
struct CScheduler : public Singleton<CScheduler>
|
||||
@ -59,15 +65,19 @@ struct CScheduler : public Singleton<CScheduler>
|
||||
std::priority_queue<SDispatchObjectScript> timeScript, frameScript;
|
||||
std::priority_queue<SDispatchObjectFunction> timeFunction, frameFunction;
|
||||
std::list<CJSProgressTimer*> progressTimers;
|
||||
int m_nextTaskId;
|
||||
bool m_abortInterval;
|
||||
std::set<int> tasksToCancel;
|
||||
|
||||
void pushTime( size_t delay, const CStrW& fragment, JSObject* operateOn = NULL );
|
||||
void pushFrame( size_t delay, const CStrW& fragment, JSObject* operateOn = NULL );
|
||||
void pushInterval( size_t first, size_t interval, const CStrW& fragment, JSObject* operateOn = NULL );
|
||||
void pushTime( size_t delay, JSFunction* function, JSObject* operateOn = NULL );
|
||||
void pushFrame( size_t delay, JSFunction* function, JSObject* operateOn = NULL );
|
||||
void pushInterval( size_t first, size_t interval, JSFunction* function, JSObject* operateOn = NULL );
|
||||
CScheduler();
|
||||
int pushTime( size_t delay, const CStrW& fragment, JSObject* operateOn = NULL );
|
||||
int pushFrame( size_t delay, const CStrW& fragment, JSObject* operateOn = NULL );
|
||||
int pushInterval( size_t first, size_t interval, const CStrW& fragment, JSObject* operateOn = NULL, int id = 0 );
|
||||
int pushTime( size_t delay, JSFunction* function, JSObject* operateOn = NULL );
|
||||
int pushFrame( size_t delay, JSFunction* function, JSObject* operateOn = NULL );
|
||||
int pushInterval( size_t first, size_t interval, JSFunction* function, JSObject* operateOn = NULL, int id = 0 );
|
||||
void pushProgressTimer( CJSProgressTimer* progressTimer );
|
||||
void cancelTask( int id );
|
||||
void update(size_t elapsedSimulationTime);
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user