33#include < scratchcpp/scratchconfiguration.h>
44#include < scratchcpp/iblocksection.h>
55#include < scratchcpp/script.h>
6+ #include < scratchcpp/sprite.h>
67#include < scratchcpp/broadcast.h>
78#include < scratchcpp/compiler.h>
89#include < scratchcpp/input.h>
@@ -111,7 +112,7 @@ void Engine::compile()
111112 if (m_scripts.count (block) == 1 ) {
112113 m_scripts[block]->setProcedures (procedureBytecodes);
113114 m_scripts[block]->setConstValues (compiler.constValues ());
114- m_scripts[block]->setVariables (compiler.variablePtrs ());
115+ m_scripts[block]->setVariables (compiler.variables ());
115116 m_scripts[block]->setLists (compiler.lists ());
116117 }
117118 }
@@ -201,22 +202,21 @@ void Engine::broadcast(unsigned int index, VirtualMachine *sourceScript, bool wa
201202 const std::vector<Script *> &scripts = m_broadcastMap[index];
202203
203204 for (auto script : scripts) {
204- long scriptIndex = - 1 ;
205- for ( long i = 0 ; i < m_runningScripts. size (); i++) {
206- if ( m_runningScripts[i]-> script () == script ) {
207- scriptIndex = i;
208- break ;
205+ std::vector<VirtualMachine *> runningBroadcastScripts ;
206+
207+ for ( auto vm : m_runningScripts) {
208+ if (vm-> script () == script) {
209+ runningBroadcastScripts. push_back (vm. get ()) ;
209210 }
210211 }
211212
212- if (scriptIndex != -1 ) {
213- // Reset the script if it's already running
214- auto vm = m_runningScripts[scriptIndex];
213+ // Reset running scripts
214+ for (VirtualMachine *vm : runningBroadcastScripts) {
215215 vm->reset ();
216216
217217 // Remove the script from scripts to remove because it's going to run again
218- m_scriptsToRemove.erase (std::remove (m_scriptsToRemove.begin (), m_scriptsToRemove.end (), vm. get () ), m_scriptsToRemove.end ());
219- assert (std::find (m_scriptsToRemove.begin (), m_scriptsToRemove.end (), m_runningScripts[scriptIndex]. get () ) == m_scriptsToRemove.end ());
218+ m_scriptsToRemove.erase (std::remove (m_scriptsToRemove.begin (), m_scriptsToRemove.end (), vm), m_scriptsToRemove.end ());
219+ assert (std::find (m_scriptsToRemove.begin (), m_scriptsToRemove.end (), vm ) == m_scriptsToRemove.end ());
220220
221221 auto &scripts = m_runningBroadcastMap[index];
222222
@@ -232,10 +232,29 @@ void Engine::broadcast(unsigned int index, VirtualMachine *sourceScript, bool wa
232232 m_skipFrame = false ;
233233 } else
234234 sourceScript->stop (true , true );
235- } else {
236- auto vm = script->start ();
237- m_runningScripts.push_back (vm);
238- m_runningBroadcastMap[index].push_back ({ sourceScript, vm.get () });
235+ }
236+
237+ // Start scripts which are not running
238+ Target *root = script->target ();
239+ std::vector<Target *> targets = { root };
240+
241+ if (!root->isStage ()) {
242+ Sprite *sprite = dynamic_cast <Sprite *>(root);
243+ assert (sprite);
244+ auto children = sprite->allChildren ();
245+
246+ for (auto child : children)
247+ targets.push_back (child.get ());
248+ }
249+
250+ for (Target *target : targets) {
251+ auto it = std::find_if (runningBroadcastScripts.begin (), runningBroadcastScripts.end (), [target](VirtualMachine *vm) { return vm->target () == target; });
252+
253+ if (it == runningBroadcastScripts.end ()) {
254+ auto vm = script->start (target);
255+ m_runningScripts.push_back (vm);
256+ m_runningBroadcastMap[index].push_back ({ sourceScript, vm.get () });
257+ }
239258 }
240259 }
241260}
@@ -258,6 +277,37 @@ void Engine::stopTarget(Target *target, VirtualMachine *exceptScript)
258277 stopScript (script);
259278}
260279
280+ void Engine::initClone (Sprite *clone)
281+ {
282+ if (!clone)
283+ return ;
284+
285+ Sprite *source = clone->cloneParent ();
286+ Target *root = clone->cloneRoot ();
287+ assert (source);
288+ assert (root);
289+
290+ if (!source || !root)
291+ return ;
292+
293+ auto it = m_cloneInitScriptsMap.find (root);
294+
295+ if (it != m_cloneInitScriptsMap.cend ()) {
296+ const auto &scripts = it->second ;
297+
298+ #ifndef NDEBUG
299+ // Since we're initializing the clone, it shouldn't have any running scripts
300+ for (const auto script : m_runningScripts)
301+ assert (script->target () != clone);
302+ #endif
303+
304+ for (auto script : scripts) {
305+ auto vm = script->start (clone);
306+ m_runningScripts.push_back (vm);
307+ }
308+ }
309+ }
310+
261311void Engine::run ()
262312{
263313 auto frameDuration = std::chrono::milliseconds (33 );
@@ -442,6 +492,7 @@ void Engine::addBroadcastScript(std::shared_ptr<Block> whenReceivedBlock, std::s
442492 auto id = findBroadcast (broadcast->name ());
443493 if (m_broadcastMap.count (id) == 1 ) {
444494 std::vector<Script *> &scripts = m_broadcastMap[id];
495+ // TODO: Do not allow adding existing scripts
445496 scripts.push_back (m_scripts[whenReceivedBlock].get ());
446497 } else {
447498 m_broadcastMap[id] = { m_scripts[whenReceivedBlock].get () };
@@ -452,6 +503,22 @@ void Engine::addBroadcastScript(std::shared_ptr<Block> whenReceivedBlock, std::s
452503 }
453504}
454505
506+ void Engine::addCloneInitScript (std::shared_ptr<Block> hatBlock)
507+ {
508+ Target *target = hatBlock->target ();
509+ Script *script = m_scripts[hatBlock].get ();
510+ auto it = m_cloneInitScriptsMap.find (target);
511+
512+ if (it == m_cloneInitScriptsMap.cend ())
513+ m_cloneInitScriptsMap[target] = { m_scripts[hatBlock].get () };
514+ else {
515+ auto &scripts = it->second ;
516+
517+ if (std::find (scripts.begin (), scripts.end (), script) == scripts.cend ())
518+ scripts.push_back (script);
519+ }
520+ }
521+
455522const std::vector<std::shared_ptr<Target>> &Engine::targets () const
456523{
457524 return m_targets;
@@ -460,14 +527,31 @@ const std::vector<std::shared_ptr<Target>> &Engine::targets() const
460527void Engine::setTargets (const std::vector<std::shared_ptr<Target>> &newTargets)
461528{
462529 m_targets = newTargets;
530+ m_variableOwners.clear ();
531+ m_listOwners.clear ();
463532
464- // Set engine and target in all blocks
465533 for (auto target : m_targets) {
534+ // Set engine in the target
535+ target->setEngine (this );
466536 auto blocks = target->blocks ();
537+
467538 for (auto block : blocks) {
539+ // Set engine and target in the block
468540 block->setEngine (this );
469541 block->setTarget (target.get ());
470542 }
543+
544+ // Add variables to owner map
545+ const auto &variables = target->variables ();
546+
547+ for (auto variable : variables)
548+ m_variableOwners[variable.get ()] = target.get ();
549+
550+ // Add lists to owner map
551+ const auto &lists = target->lists ();
552+
553+ for (auto list : lists)
554+ m_listOwners[list.get ()] = target.get ();
471555 }
472556}
473557
@@ -490,6 +574,26 @@ int Engine::findTarget(const std::string &targetName) const
490574 return -1 ;
491575}
492576
577+ Target *Engine::variableOwner (Variable *variable) const
578+ {
579+ auto it = m_variableOwners.find (variable);
580+
581+ if (it == m_variableOwners.cend ())
582+ return nullptr ;
583+
584+ return it->second ;
585+ }
586+
587+ Target *Engine::listOwner (List *list) const
588+ {
589+ auto it = m_listOwners.find (list);
590+
591+ if (it == m_listOwners.cend ())
592+ return nullptr ;
593+
594+ return it->second ;
595+ }
596+
493597const std::vector<std::string> &Engine::extensions () const
494598{
495599 return m_extensions;
0 commit comments