#include "precompiled.h" #include "Scheduler.h" #include "Entity.h" size_t simulationTime; size_t frameCount; /* void CScheduler::pushTime( size_t delay, const HEntity& destination, const CMessage* message ) { timeMessage.push( SDispatchObjectMessage( destination, simulationTime + delay, message ) ); } void CScheduler::pushFrame( size_t delay, const HEntity& destination, const CMessage* message ) { frameMessage.push( SDispatchObjectMessage( destination, frameCount + delay, message ) ); } */ CScheduler::CScheduler() { m_nextTaskId = 1; } int CScheduler::pushTime( size_t delay, const CStrW& fragment, JSObject* operateOn ) { timeScript.push( SDispatchObjectScript( m_nextTaskId, fragment, simulationTime + delay, operateOn ) ); return m_nextTaskId++; } int CScheduler::pushFrame( size_t delay, const CStrW& fragment, JSObject* operateOn ) { frameScript.push( SDispatchObjectScript( m_nextTaskId, fragment, frameCount + delay, operateOn ) ); return m_nextTaskId++; } int CScheduler::pushInterval( size_t first, size_t interval, const CStrW& fragment, JSObject* operateOn, int id ) { if( !id ) id = m_nextTaskId++; timeScript.push( SDispatchObjectScript( id, fragment, simulationTime + first, operateOn, interval ) ); return id++; } int CScheduler::pushTime( size_t delay, JSFunction* script, JSObject* operateOn ) { timeFunction.push( SDispatchObjectFunction( m_nextTaskId, script, simulationTime + delay, operateOn ) ); return m_nextTaskId++; } int CScheduler::pushFrame( size_t delay, JSFunction* script, JSObject* operateOn ) { 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 ) { progressTimers.push_back( progressTimer ); } void CScheduler::cancelTask( int id ) { tasksToCancel.insert( id ); } void CScheduler::update(size_t simElapsed) { simulationTime += simElapsed; frameCount++; jsval rval; while( !timeScript.empty() ) { SDispatchObjectScript top = timeScript.top(); if( top.deliveryTime > simulationTime ) 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, top.id ); } while( !frameScript.empty() ) { SDispatchObjectScript top = frameScript.top(); 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() ) { SDispatchObjectFunction top = timeFunction.top(); if( top.deliveryTime > simulationTime ) break; 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, top.id ); } while( !frameFunction.empty() ) { SDispatchObjectFunction top = frameFunction.top(); if( top.deliveryTime > frameCount ) 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 ); } std::list::iterator it; for( it = progressTimers.begin(); it != progressTimers.end(); it++ ) { (*it)->m_Current += (*it)->m_Increment * simElapsed; if( (*it)->m_Current >= (*it)->m_Max ) { (*it)->m_Current = (*it)->m_Max; if( (*it)->m_Callback ) JS_CallFunction( g_ScriptingHost.GetContext(), (*it)->m_OperateOn, (*it)->m_Callback, 0, NULL, &rval ); it = progressTimers.erase( it ); } } } CJSProgressTimer::CJSProgressTimer( double Max, double Increment, JSFunction* Callback, JSObject* OperateOn ) { m_Max = Max; m_Increment = Increment; m_Callback = Callback; m_OperateOn = OperateOn; m_Current = 0.0; } void CJSProgressTimer::ScriptingInit() { AddProperty( L"max", &CJSProgressTimer::m_Max ); AddProperty( L"current", &CJSProgressTimer::m_Current ); AddProperty( L"increment", &CJSProgressTimer::m_Increment ); CJSObject::ScriptingInit( "ProgressTimer", Construct, 2 ); } JSBool CJSProgressTimer::Construct( JSContext* cx, JSObject* UNUSED(obj), uint argc, jsval* argv, jsval* rval ) { debug_assert( argc >= 2 ); double max = ToPrimitive( argv[0] ); double increment = ToPrimitive( argv[1] ); JSFunction* callback_fn = NULL; JSObject* scope_obj = NULL; if( argc >= 3 ) { callback_fn = JS_ValueToFunction( cx, argv[2] ); if( ( argc >= 4 ) && JSVAL_IS_OBJECT( argv[3] ) ) { scope_obj = JSVAL_TO_OBJECT( argv[3] ); } else { // Attempt to determine object to operate on automatically. // SpiderMonkey docs say the 'this' parameter of the calling // function is in argv[-2]. Do I believe them? One way to find out. scope_obj = JSVAL_TO_OBJECT( argv[-2] ); } } CJSProgressTimer* timer = new CJSProgressTimer( max, increment, callback_fn, scope_obj ); timer->m_EngineOwned = false; g_Scheduler.pushProgressTimer( timer ); *rval = OBJECT_TO_JSVAL( timer->GetScript() ); return( JS_TRUE ); }