/** * This function calls any script timers which have expired by now */ void tick( double timeNow ) { const int MAX_TIMER_CALLS_PER_FRAME = 1000; Timers timersToCall; Timers::iterator iter = gTimers.begin(); while ( iter != gTimers.end() ) { if ( iter->time <= timeNow ) { timersToCall.push_back( *iter ); iter = gTimers.erase( iter ); } else { ++iter; } } // Using a reverse iterator, since the TimerRecord comparison operator causes // the sorted list to be in reverse order (earlier timers are later in the list). stable_sort( timersToCall.begin(), timersToCall.end() ); int numExpired = 0; Timers::reverse_iterator revIter = timersToCall.rbegin(); for ( ; revIter != timersToCall.rend() && numExpired < MAX_TIMER_CALLS_PER_FRAME; ++revIter ) { TimerRecord& timer = *revIter; gFreeTimerHandles.push( timer.handle ); Script::call( timer.function, timer.arguments, timer.source ); // Script::call decrefs timer.function and timer.arguments for us numExpired++; } if (numExpired >= MAX_TIMER_CALLS_PER_FRAME) { // If there are too many to run this frame, put the remainder back into the main list. for ( ; revIter != timersToCall.rend(); ++revIter ) { TimerRecord& timer = *revIter; gTimers.push_back( timer ); } //ERROR_MSG( "BigWorldClientScript::tick: Loop interrupted because" // " too many timers (> %d) wanted to expire this frame!", // numExpired ); } }
Timer::Timer(int interval, Widget* owner) : m_owner(owner ? owner: Manager::getDefault()) , m_interval(interval) , m_lastTime(-1) { ASSERT(m_owner != NULL); timers.push_back(this); }
Timer::Timer(int interval, Widget* owner) : m_owner(owner ? owner: Manager::getDefault()) , m_interval(interval) , m_running(false) , m_lastTick(0) { ASSERT(m_owner != nullptr); assert_ui_thread(); timers.push_back(this); }
/** * This function adds a script 'timer' to be called next tick * * It is used by routines which want to make script calls but can't * because they're in the middle of something scripts might mess up * (like iterating over the scene to tick or draw it) * * The optional age parameter specifies the age of the call, * i.e. how far in the past it wanted to be made. * Older calls are called back first. * * @note: This function steals the references to both fn and args */ void callNextFrame( PyObject * fn, PyObject * args, const char * reason, double age ) { TimerHandle handle; if(!gFreeTimerHandles.empty()) { handle = gFreeTimerHandles.top(); handle.issueCount++; gFreeTimerHandles.pop(); } else { if (gTimers.size() >= USHRT_MAX) { PyErr_SetString( PyExc_TypeError, "callNextFrame: Callback handle overflow." ); return; } handle.id = gTimers.size() + 1; handle.issueCount = 1; } TimerRecord newTR = { getTotalGameTime() - age, fn, args, reason, { handle.i32 } }; gTimers.push_back( newTR ); }