@@ -136,52 +136,6 @@ void Engine::compile()
136136 }
137137}
138138
139- void Engine::frame ()
140- {
141- m_lockFrame = false ;
142-
143- for (int i = 0 ; i < m_runningScripts.size (); i++) {
144- auto script = m_runningScripts[i];
145- m_breakFrame = false ;
146-
147- do {
148- script->run ();
149- if (script->atEnd () && m_running) {
150- for (auto &[key, value] : m_runningBroadcastMap) {
151- size_t index = 0 ;
152-
153- for (const auto &pair : value) {
154- if (pair.second == script.get ()) {
155- value.erase (value.begin () + index);
156- break ;
157- }
158-
159- index++;
160- }
161- }
162-
163- if (std::find (m_scriptsToRemove.begin (), m_scriptsToRemove.end (), script.get ()) == m_scriptsToRemove.end ())
164- m_scriptsToRemove.push_back (script.get ());
165- }
166- } while (!script->atEnd () && !m_breakFrame);
167- }
168-
169- assert (m_running || m_scriptsToRemove.empty ());
170-
171- for (auto script : m_scriptsToRemove) {
172- size_t index = -1 ;
173- for (size_t i = 0 ; i < m_runningScripts.size (); i++) {
174- if (m_runningScripts[i].get () == script) {
175- index = i;
176- break ;
177- }
178- }
179- assert (index != -1 );
180- m_runningScripts.erase (m_runningScripts.begin () + index);
181- }
182- m_scriptsToRemove.clear ();
183- }
184-
185139void Engine::start ()
186140{
187141 // NOTE: Running scripts should be deleted, but this method will probably be removed anyway
@@ -221,7 +175,7 @@ void Engine::startScript(std::shared_ptr<Block> topLevelBlock, std::shared_ptr<T
221175
222176 if (topLevelBlock->next ()) {
223177 auto script = m_scripts[topLevelBlock];
224- m_runningScripts. push_back (script->start ());
178+ addRunningScript (script->start ());
225179 }
226180}
227181
@@ -290,7 +244,7 @@ void Engine::broadcastByPtr(Broadcast *broadcast, VirtualMachine *sourceScript,
290244
291245 if (it == runningBroadcastScripts.end ()) {
292246 auto vm = script->start (target);
293- m_runningScripts. push_back (vm);
247+ addRunningScript (vm);
294248 m_runningBroadcastMap[broadcast].push_back ({ sourceScript, vm.get () });
295249 }
296250 }
@@ -342,7 +296,7 @@ void Engine::initClone(Sprite *clone)
342296
343297 for (auto script : scripts) {
344298 auto vm = script->start (clone);
345- m_runningScripts. push_back (vm);
299+ addRunningScript (vm);
346300 }
347301 }
348302
@@ -357,35 +311,110 @@ void Engine::deinitClone(Sprite *clone)
357311
358312void Engine::run ()
359313{
360- updateFrameDuration ();
361314 start ();
315+ eventLoop (true );
316+ finalize ();
317+ }
318+
319+ void Engine::runEventLoop ()
320+ {
321+ eventLoop ();
322+ }
323+
324+ void Engine::eventLoop (bool untilProjectStops)
325+ {
326+ updateFrameDuration ();
327+ m_newScripts.clear ();
362328
363329 while (true ) {
364- auto lastFrameTime = m_clock->currentSteadyTime ();
365- m_skipFrame = false ;
330+ auto frameStart = m_clock->currentSteadyTime ();
331+ std::chrono::steady_clock::time_point currentTime;
332+ std::chrono::milliseconds elapsedTime, sleepTime;
333+ m_lockFrame = false ;
334+ m_redrawRequested = false ;
335+ bool timeout = false ;
336+ bool stop = false ;
337+ std::vector<std::shared_ptr<VirtualMachine>> scripts = m_runningScripts; // this must be copied
338+
339+ do {
340+ m_scriptsToRemove.clear ();
341+
342+ // Execute new scripts from last frame
343+ runScripts (m_newScripts, scripts);
344+
345+ // Execute all running scripts
346+ m_newScripts.clear ();
347+ runScripts (scripts, scripts);
348+
349+ // Stop the event loop if the project has finished running (and untilProjectStops is set to true)
350+ if (untilProjectStops && m_runningScripts.empty ()) {
351+ stop = true ;
352+ break ;
353+ }
354+
355+ currentTime = m_clock->currentSteadyTime ();
356+ elapsedTime = std::chrono::duration_cast<std::chrono::milliseconds>(currentTime - frameStart);
357+ sleepTime = m_frameDuration - elapsedTime;
358+ timeout = sleepTime <= std::chrono::milliseconds::zero ();
359+ } while (!m_redrawRequested && !timeout && !stop);
366360
367- // Execute the frame
368- frame ();
369- if (m_runningScripts.size () <= 0 )
361+ if (stop)
370362 break ;
371363
372- // Sleep until the time for the next frame
373- auto currentTime = m_clock->currentSteadyTime ();
374- auto elapsedTime = std::chrono::duration_cast<std::chrono::milliseconds>(currentTime - lastFrameTime);
375- auto sleepTime = m_frameDuration - elapsedTime;
376- bool timeOut = sleepTime <= std::chrono::milliseconds::zero ();
364+ // Redraw
365+ // TODO: Redraw here
377366
378- if (!timeOut && !m_skipFrame)
367+ // If the timeout hasn't been reached yet (redraw was requested), sleep
368+ if (!timeout)
379369 m_clock->sleep (sleepTime);
370+ }
380371
381- if ((m_skipFrame && timeOut) || !m_skipFrame) {
382- // TODO: Repaint here
383- }
372+ finalize ();
373+ }
374+
375+ void Engine::runScripts (const std::vector<std::shared_ptr<VirtualMachine>> &scripts, std::vector<std::shared_ptr<VirtualMachine>> &globalScripts)
376+ {
377+ // globalScripts is used to remove "scripts to remove" from it so that they're removed from the correct list
378+ for (int i = 0 ; i < scripts.size (); i++) {
379+ auto script = scripts[i];
380+ assert (script);
381+ m_breakFrame = false ;
384382
385- lastFrameTime = currentTime;
383+ do {
384+ script->run ();
385+ if (script->atEnd () && m_running) {
386+ for (auto &[key, value] : m_runningBroadcastMap) {
387+ size_t index = 0 ;
388+
389+ for (const auto &pair : value) {
390+ if (pair.second == script.get ()) {
391+ value.erase (value.begin () + index);
392+ break ;
393+ }
394+
395+ index++;
396+ }
397+ }
398+
399+ if (std::find (m_scriptsToRemove.begin (), m_scriptsToRemove.end (), script.get ()) == m_scriptsToRemove.end ())
400+ m_scriptsToRemove.push_back (script.get ());
401+ }
402+ } while (!script->atEnd () && !m_breakFrame);
386403 }
387404
388- finalize ();
405+ assert (m_running || m_scriptsToRemove.empty ());
406+
407+ for (auto script : m_scriptsToRemove) {
408+ auto pred = [script](std::shared_ptr<VirtualMachine> vm) { return vm.get () == script; };
409+ auto it1 = std::find_if (m_runningScripts.begin (), m_runningScripts.end (), pred);
410+ auto it2 = std::find_if (globalScripts.begin (), globalScripts.end (), pred);
411+ assert (it1 != m_runningScripts.end ());
412+ m_runningScripts.erase (it1);
413+
414+ if (it2 != globalScripts.end ())
415+ globalScripts.erase (it2);
416+ }
417+ m_scriptsToRemove.clear ();
389418}
390419
391420bool Engine::isRunning () const
@@ -984,6 +1013,12 @@ void Engine::updateFrameDuration()
9841013 m_frameDuration = std::chrono::milliseconds (static_cast <long >(1000 / m_fps));
9851014}
9861015
1016+ void Engine::addRunningScript (std::shared_ptr<VirtualMachine> vm)
1017+ {
1018+ m_runningScripts.push_back (vm);
1019+ m_newScripts.push_back (vm);
1020+ }
1021+
9871022void Engine::startWhenKeyPressedScripts (const std::vector<Script *> &scripts)
9881023{
9891024 for (auto script : scripts) {
0 commit comments