Skip to content

Commit eaa4b6e

Browse files
committed
Execute targets in layer order
1 parent b07ee25 commit eaa4b6e

File tree

2 files changed

+132
-40
lines changed

2 files changed

+132
-40
lines changed

src/engine/internal/engine.cpp

Lines changed: 125 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,15 @@ Engine::Engine() :
3636
Engine::~Engine()
3737
{
3838
m_clones.clear();
39+
m_executableTargets.clear();
3940
}
4041

4142
void 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

251255
void 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

297307
void 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

302313
void 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
751809
void 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

768832
Target *Engine::targetAt(int index) const
@@ -951,6 +1015,7 @@ void Engine::finalize()
9511015

9521016
void 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+
9701042
void Engine::updateFrameDuration()
9711043
{
9721044
m_frameDuration = std::chrono::milliseconds(static_cast<long>(1000 / m_fps));
9731045
}
9741046

9751047
void 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

9811069
void Engine::startWhenKeyPressedScripts(const std::vector<Script *> &scripts)

src/engine/internal/engine.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,10 +116,13 @@ class Engine : public IEngine
116116
IClock *m_clock = nullptr;
117117

118118
private:
119+
using TargetScriptMap = std::unordered_map<Target *, std::vector<std::shared_ptr<VirtualMachine>>>;
120+
119121
void eventLoop(bool untilProjectStops = false);
120-
void runScripts(const std::vector<std::shared_ptr<VirtualMachine>> &scripts, std::vector<std::shared_ptr<VirtualMachine>> &globalScripts);
122+
void runScripts(const TargetScriptMap &scriptMap, TargetScriptMap &globalScriptMap);
121123
void finalize();
122124
void deleteClones();
125+
void removeExecutableClones();
123126
std::shared_ptr<Block> getBlock(const std::string &id);
124127
std::shared_ptr<Variable> getVariable(const std::string &id);
125128
std::shared_ptr<List> getList(const std::string &id);
@@ -139,8 +142,9 @@ class Engine : public IEngine
139142
std::unordered_map<Target *, std::vector<Script *>> m_cloneInitScriptsMap; // target (no clones), "when I start as a clone" scripts
140143
std::unordered_map<std::string, std::vector<Script *>> m_whenKeyPressedScripts; // key name, "when key pressed" scripts
141144
std::vector<std::string> m_extensions;
142-
std::vector<std::shared_ptr<VirtualMachine>> m_runningScripts;
143-
std::vector<std::shared_ptr<VirtualMachine>> m_newScripts;
145+
std::vector<Target *> m_executableTargets; // sorted by layer (reverse order of execution)
146+
std::unordered_map<Target *, std::vector<std::shared_ptr<VirtualMachine>>> m_runningScripts;
147+
std::unordered_map<Target *, std::vector<std::shared_ptr<VirtualMachine>>> m_newScripts;
144148
std::vector<VirtualMachine *> m_scriptsToRemove;
145149
std::unordered_map<std::shared_ptr<Block>, std::shared_ptr<Script>> m_scripts;
146150
std::vector<BlockFunc> m_functions;

0 commit comments

Comments
 (0)