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:
Matei 2005-12-18 07:33:16 +00:00
parent 8f5b5b7b73
commit 5e0e3c32f3
4 changed files with 1395 additions and 1240 deletions

View File

@ -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

View File

@ -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 );
}

View File

@ -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);
};