@@ -36,13 +36,15 @@ Engine::Engine() :
3636Engine::~Engine ()
3737{
3838 m_clones.clear ();
39+ m_executableTargets.clear ();
3940}
4041
4142void Engine::clear ()
4243{
4344 m_sections.clear ();
4445 m_targets.clear ();
4546 m_broadcasts.clear ();
47+ removeExecutableClones ();
4648 m_clones.clear ();
4749
4850 m_running = false ;
@@ -191,9 +193,11 @@ void Engine::broadcastByPtr(Broadcast *broadcast, VirtualMachine *sourceScript,
191193 for (auto script : scripts) {
192194 std::vector<VirtualMachine *> runningBroadcastScripts;
193195
194- for (auto vm : m_runningScripts) {
195- if (vm->script () == script) {
196- runningBroadcastScripts.push_back (vm.get ());
196+ for (const auto &[target, targetScripts] : m_runningScripts) {
197+ for (auto vm : targetScripts) {
198+ if (vm->script () == script) {
199+ runningBroadcastScripts.push_back (vm.get ());
200+ }
197201 }
198202 }
199203
@@ -250,8 +254,10 @@ void Engine::stopScript(VirtualMachine *vm)
250254
251255void Engine::stopTarget (Target *target, VirtualMachine *exceptScript)
252256{
257+ const auto &targetScripts = m_runningScripts[target];
253258 std::vector<VirtualMachine *> scripts;
254- for (auto script : m_runningScripts) {
259+
260+ for (auto script : targetScripts) {
255261 if ((script->target () == target) && (script.get () != exceptScript))
256262 scripts.push_back (script.get ());
257263 }
@@ -280,8 +286,10 @@ void Engine::initClone(Sprite *clone)
280286
281287#ifndef NDEBUG
282288 // Since we're initializing the clone, it shouldn't have any running scripts
283- for (const auto script : m_runningScripts)
284- assert ((script->target () != clone) || (std::find (m_scriptsToRemove.begin (), m_scriptsToRemove.end (), script.get ()) != m_scriptsToRemove.end ()));
289+ for (const auto &[target, targetScripts] : m_runningScripts) {
290+ for (const auto script : targetScripts)
291+ assert ((target != clone) || (std::find (m_scriptsToRemove.begin (), m_scriptsToRemove.end (), script.get ()) != m_scriptsToRemove.end ()));
292+ }
285293#endif
286294
287295 for (auto script : scripts) {
@@ -291,12 +299,15 @@ void Engine::initClone(Sprite *clone)
291299 }
292300
293301 assert (std::find (m_clones.begin (), m_clones.end (), clone) == m_clones.end ());
302+ assert (std::find (m_executableTargets.begin (), m_executableTargets.end (), clone) == m_executableTargets.end ());
294303 m_clones.push_back (clone);
304+ m_executableTargets.push_back (clone); // execution order needs to be updated after this
295305}
296306
297307void Engine::deinitClone (Sprite *clone)
298308{
299309 m_clones.erase (std::remove (m_clones.begin (), m_clones.end (), clone), m_clones.end ());
310+ m_executableTargets.erase (std::remove (m_executableTargets.begin (), m_executableTargets.end (), clone), m_executableTargets.end ());
300311}
301312
302313void Engine::run ()
@@ -323,7 +334,8 @@ void Engine::eventLoop(bool untilProjectStops)
323334 m_redrawRequested = false ;
324335 bool timeout = false ;
325336 bool stop = false ;
326- std::vector<std::shared_ptr<VirtualMachine>> scripts = m_runningScripts; // this must be copied
337+ // TODO: Avoid copying by passing current size to runScripts()
338+ TargetScriptMap scripts = m_runningScripts; // this must be copied (for now)
327339
328340 do {
329341 m_scriptsToRemove.clear ();
@@ -336,9 +348,20 @@ void Engine::eventLoop(bool untilProjectStops)
336348 runScripts (scripts, scripts);
337349
338350 // Stop the event loop if the project has finished running (and untilProjectStops is set to true)
339- if (untilProjectStops && m_runningScripts.empty ()) {
340- stop = true ;
341- break ;
351+ if (untilProjectStops) {
352+ bool empty = true ;
353+
354+ for (const auto &pair : m_runningScripts) {
355+ if (!pair.second .empty ()) {
356+ empty = false ;
357+ break ;
358+ }
359+ }
360+
361+ if (empty) {
362+ stop = true ;
363+ break ;
364+ }
342365 }
343366
344367 currentTime = m_clock->currentSteadyTime ();
@@ -361,44 +384,79 @@ void Engine::eventLoop(bool untilProjectStops)
361384 finalize ();
362385}
363386
364- void Engine::runScripts (const std::vector<std::shared_ptr<VirtualMachine>> &scripts, std::vector<std::shared_ptr<VirtualMachine>> &globalScripts )
387+ void Engine::runScripts (const TargetScriptMap &scriptMap, TargetScriptMap &globalScriptMap )
365388{
366- // globalScripts is used to remove "scripts to remove" from it so that they're removed from the correct list
367- for (int i = 0 ; i < scripts.size (); i++) {
368- auto script = scripts[i];
369- assert (script);
389+ // globalScriptMap is used to remove "scripts to remove" from it so that they're removed from the correct list
390+ for (int i = m_executableTargets.size () - 1 ; i >= 0 ; i--) {
391+ auto it = scriptMap.find (m_executableTargets[i]);
370392
371- script->run ();
372- if (script->atEnd () && m_running) {
373- for (auto &[key, value] : m_runningBroadcastMap) {
374- size_t index = 0 ;
393+ if ((it == scriptMap.cend ()) || it->second .empty ())
394+ continue ; // skip the target if it doesn't have any running script
375395
376- for (const auto &pair : value) {
377- if (pair.second == script.get ()) {
378- value.erase (value.begin () + index);
379- break ;
380- }
396+ const auto &scripts = it->second ;
381397
382- index++;
383- }
384- }
398+ for (int i = 0 ; i < scripts.size (); i++) {
399+ auto script = scripts[i];
400+ assert (script);
401+
402+ if (std::find (m_scriptsToRemove.begin (), m_scriptsToRemove.end (), script.get ()) != m_scriptsToRemove.end ())
403+ continue ; // skip the script if it is scheduled to be removed
385404
386- if (std::find (m_scriptsToRemove.begin (), m_scriptsToRemove.end (), script.get ()) == m_scriptsToRemove.end ())
387- m_scriptsToRemove.push_back (script.get ());
405+ script->run ();
406+
407+ if (script->atEnd () && m_running) {
408+ if (std::find (m_scriptsToRemove.begin (), m_scriptsToRemove.end (), script.get ()) == m_scriptsToRemove.end ())
409+ m_scriptsToRemove.push_back (script.get ());
410+ }
388411 }
389412 }
390413
391414 assert (m_running || m_scriptsToRemove.empty ());
392415
393416 for (auto script : m_scriptsToRemove) {
394417 auto pred = [script](std::shared_ptr<VirtualMachine> vm) { return vm.get () == script; };
395- auto it1 = std::find_if (m_runningScripts.begin (), m_runningScripts.end (), pred);
396- auto it2 = std::find_if (globalScripts.begin (), globalScripts.end (), pred);
397- assert (it1 != m_runningScripts.end ());
398- m_runningScripts.erase (it1);
418+ #ifndef NDEBUG
419+ bool found = false ;
420+ #endif
421+
422+ // Remove from m_runningScripts
423+ for (auto &[target, scripts] : m_runningScripts) {
424+ auto it = std::find_if (scripts.begin (), scripts.end (), pred);
399425
400- if (it2 != globalScripts.end ())
401- globalScripts.erase (it2);
426+ if (it != scripts.end ()) {
427+ scripts.erase (it);
428+ #ifndef NDEBUG
429+ found = true ;
430+ #endif
431+ break ;
432+ }
433+ }
434+
435+ assert (found);
436+
437+ // Remove from globalScriptMap
438+ for (auto &[target, scripts] : globalScriptMap) {
439+ auto it = std::find_if (scripts.begin (), scripts.end (), pred);
440+
441+ if (it != scripts.end ()) {
442+ scripts.erase (it);
443+ break ;
444+ }
445+ }
446+
447+ // Remove from m_runningBroadcastMap
448+ for (auto &[broadcast, pairs] : m_runningBroadcastMap) {
449+ size_t index = 0 ;
450+
451+ for (const auto &pair : pairs) {
452+ if (pair.second == script) {
453+ pairs.erase (pairs.begin () + index);
454+ break ;
455+ }
456+
457+ index++;
458+ }
459+ }
402460 }
403461 m_scriptsToRemove.clear ();
404462}
@@ -751,8 +809,11 @@ const std::vector<std::shared_ptr<Target>> &Engine::targets() const
751809void Engine::setTargets (const std::vector<std::shared_ptr<Target>> &newTargets)
752810{
753811 m_targets = newTargets;
812+ m_executableTargets.clear ();
754813
755814 for (auto target : m_targets) {
815+ m_executableTargets.push_back (target.get ());
816+
756817 // Set engine in the target
757818 target->setEngine (this );
758819 auto blocks = target->blocks ();
@@ -763,6 +824,9 @@ void Engine::setTargets(const std::vector<std::shared_ptr<Target>> &newTargets)
763824 block->setTarget (target.get ());
764825 }
765826 }
827+
828+ // Sort the executable targets by layer order
829+ std::sort (m_executableTargets.begin (), m_executableTargets.end (), [](Target *t1, Target *t2) { return t1->layerOrder () < t2->layerOrder (); });
766830}
767831
768832Target *Engine::targetAt (int index) const
@@ -951,6 +1015,7 @@ void Engine::finalize()
9511015
9521016void Engine::deleteClones ()
9531017{
1018+ removeExecutableClones ();
9541019 m_clones.clear ();
9551020
9561021 for (auto target : m_targets) {
@@ -967,15 +1032,38 @@ void Engine::deleteClones()
9671032 }
9681033}
9691034
1035+ void Engine::removeExecutableClones ()
1036+ {
1037+ // Remove clones from the executable targets
1038+ for (Target *target : m_clones)
1039+ m_executableTargets.erase (std::remove (m_executableTargets.begin (), m_executableTargets.end (), target), m_executableTargets.end ());
1040+ }
1041+
9701042void Engine::updateFrameDuration ()
9711043{
9721044 m_frameDuration = std::chrono::milliseconds (static_cast <long >(1000 / m_fps));
9731045}
9741046
9751047void Engine::addRunningScript (std::shared_ptr<VirtualMachine> vm)
9761048{
977- m_runningScripts.push_back (vm);
978- m_newScripts.push_back (vm);
1049+ Target *target = vm->target ();
1050+ assert (vm->target ());
1051+ auto it1 = m_runningScripts.find (target);
1052+ auto it2 = m_newScripts.find (target);
1053+
1054+ if (it1 == m_runningScripts.cend ())
1055+ m_runningScripts[target] = { vm };
1056+ else {
1057+ assert (std::find (it1->second .begin (), it1->second .end (), vm) == it1->second .end ());
1058+ it1->second .push_back (vm);
1059+ }
1060+
1061+ if (it2 == m_newScripts.cend ())
1062+ m_newScripts[target] = { vm };
1063+ else {
1064+ assert (std::find (it2->second .begin (), it2->second .end (), vm) == it2->second .end ());
1065+ it2->second .push_back (vm);
1066+ }
9791067}
9801068
9811069void Engine::startWhenKeyPressedScripts (const std::vector<Script *> &scripts)
0 commit comments