@@ -433,22 +433,24 @@ VirtualMachine *Engine::startScript(std::shared_ptr<Block> topLevelBlock, Target
433433 return pushThread (topLevelBlock, target).get ();
434434}
435435
436- void Engine::broadcast (int index)
436+ void Engine::broadcast (int index, VirtualMachine *sender )
437437{
438438 if (index < 0 || index >= m_broadcasts.size ())
439439 return ;
440440
441- broadcastByPtr (m_broadcasts[index].get ());
441+ broadcastByPtr (m_broadcasts[index].get (), sender );
442442}
443443
444- void Engine::broadcastByPtr (Broadcast *broadcast)
444+ void Engine::broadcastByPtr (Broadcast *broadcast, VirtualMachine *sender )
445445{
446446 startHats (HatType::BroadcastReceived, { { HatField::BroadcastOption, broadcast } }, nullptr );
447+ addBroadcastPromise (broadcast, sender);
447448}
448449
449- void Engine::startBackdropScripts (Broadcast *broadcast)
450+ void Engine::startBackdropScripts (Broadcast *broadcast, VirtualMachine *sender )
450451{
451452 startHats (HatType::BackdropChanged, { { HatField::Backdrop, broadcast->name () } }, nullptr );
453+ addBroadcastPromise (broadcast, sender);
452454}
453455
454456void Engine::stopScript (VirtualMachine *vm)
@@ -583,6 +585,47 @@ void Engine::step()
583585 // Check running threads (must be done here)
584586 m_frameActivity = !m_threads.empty ();
585587
588+ // Resolve stopped broadcast scripts
589+ std::vector<Broadcast *> resolved;
590+
591+ for (const auto &[broadcast, senderThread] : m_broadcastSenders) {
592+ std::unordered_map<Broadcast *, std::vector<Script *>> *broadcastMap = nullptr ;
593+
594+ if (broadcast->isBackdropBroadcast ()) {
595+ // This broadcast belongs to a backdrop
596+ assert (m_broadcastMap.find (broadcast) == m_broadcastMap.cend ());
597+ broadcastMap = &m_backdropBroadcastMap;
598+ } else {
599+ // This is a regular broadcast
600+ assert (m_backdropBroadcastMap.find (broadcast) == m_backdropBroadcastMap.cend ());
601+ broadcastMap = &m_broadcastMap;
602+ }
603+
604+ std::vector<Script *> empty;
605+ const std::vector<Script *> &scripts = (broadcastMap->find (broadcast) != broadcastMap->cend ()) ? (*broadcastMap)[broadcast] : empty;
606+ // const auto &scripts = (*broadcastMap)[broadcast];
607+ bool found = false ;
608+
609+ for (auto script : scripts) {
610+ if (std::find_if (m_threads.begin (), m_threads.end (), [script](std::shared_ptr<VirtualMachine> thread) { return thread->script () == script; }) != m_threads.end ()) {
611+ found = true ;
612+ break ;
613+ }
614+ }
615+
616+ if (!found) {
617+ VirtualMachine *th = senderThread;
618+
619+ if (std::find_if (m_threads.begin (), m_threads.end (), [th](std::shared_ptr<VirtualMachine> thread) { return thread.get () == th; }) != m_threads.end ())
620+ th->resolvePromise ();
621+
622+ resolved.push_back (broadcast);
623+ }
624+ }
625+
626+ for (Broadcast *broadcast : resolved)
627+ m_broadcastSenders.erase (broadcast);
628+
586629 m_redrawRequested = false ;
587630
588631 // Step threads
@@ -1896,6 +1939,20 @@ void Engine::addRunningScript(std::shared_ptr<VirtualMachine> vm)
18961939 m_threads.push_back (vm);
18971940}
18981941
1942+ void Engine::addBroadcastPromise (Broadcast *broadcast, VirtualMachine *sender)
1943+ {
1944+ assert (broadcast);
1945+ assert (sender);
1946+
1947+ // Resolve broadcast promise if it's already running
1948+ auto it = m_broadcastSenders.find (broadcast);
1949+
1950+ if (it != m_broadcastSenders.cend () && std::find_if (m_threads.begin (), m_threads.end (), [&it](std::shared_ptr<VirtualMachine> thread) { return thread.get () == it->second ; }) != m_threads.end ())
1951+ it->second ->resolvePromise ();
1952+
1953+ m_broadcastSenders[broadcast] = sender;
1954+ }
1955+
18991956std::shared_ptr<VirtualMachine> Engine::pushThread (std::shared_ptr<Block> block, Target *target)
19001957{
19011958 // https://github.com/scratchfoundation/scratch-vm/blob/f1aa92fad79af17d9dd1c41eeeadca099339a9f1/src/engine/runtime.js#L1649-L1661
0 commit comments