Skip to content

Commit 9976e7a

Browse files
committed
fix #563: Refactor broadcasts to use promise API
1 parent 16999e7 commit 9976e7a

File tree

12 files changed

+245
-319
lines changed

12 files changed

+245
-319
lines changed

include/scratchcpp/iengine.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,13 @@ class LIBSCRATCHCPP_EXPORT IEngine
6161
virtual VirtualMachine *startScript(std::shared_ptr<Block> topLevelBlock, Target *) = 0;
6262

6363
/*! Starts the scripts of the broadcast with the given index. */
64-
virtual void broadcast(int index) = 0;
64+
virtual void broadcast(int index, VirtualMachine *sender) = 0;
6565

6666
/*! Starts the scripts of the given broadcast. */
67-
virtual void broadcastByPtr(Broadcast *broadcast) = 0;
67+
virtual void broadcastByPtr(Broadcast *broadcast, VirtualMachine *sender) = 0;
6868

6969
/*! Starts the "when backdrop switches to" scripts for the given backdrop broadcast. */
70-
virtual void startBackdropScripts(Broadcast *broadcast) = 0;
70+
virtual void startBackdropScripts(Broadcast *broadcast, VirtualMachine *sender) = 0;
7171

7272
/*! Stops the given script. */
7373
virtual void stopScript(VirtualMachine *vm) = 0;

src/blocks/eventblocks.cpp

Lines changed: 6 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -113,26 +113,8 @@ void EventBlocks::compileBroadcast(Compiler *compiler)
113113

114114
void EventBlocks::compileBroadcastAndWait(Compiler *compiler)
115115
{
116-
auto input = compiler->input(BROADCAST_INPUT);
117-
118-
if (input->type() != Input::Type::ObscuredShadow) {
119-
std::vector<int> broadcasts = compiler->engine()->findBroadcasts(input->primaryValue()->value().toString());
120-
121-
for (int index : broadcasts) {
122-
compiler->addConstValue(index);
123-
compiler->addFunctionCall(&broadcastByIndexAndWait);
124-
}
125-
126-
for (int index : broadcasts) {
127-
compiler->addConstValue(index);
128-
compiler->addFunctionCall(&checkBroadcastByIndex);
129-
}
130-
} else {
131-
compiler->addInput(input);
132-
compiler->addFunctionCall(&broadcastAndWait);
133-
compiler->addInput(input);
134-
compiler->addFunctionCall(&checkBroadcast);
135-
}
116+
compiler->addInput(BROADCAST_INPUT);
117+
compiler->addFunctionCall(&broadcastAndWait);
136118
}
137119

138120
void EventBlocks::compileWhenBroadcastReceived(Compiler *compiler)
@@ -210,14 +192,14 @@ unsigned int EventBlocks::broadcast(VirtualMachine *vm)
210192
std::vector<int> broadcasts = vm->engine()->findBroadcasts(vm->getInput(0, 1)->toString());
211193

212194
for (int index : broadcasts)
213-
vm->engine()->broadcast(index);
195+
vm->engine()->broadcast(index, vm);
214196

215197
return 1;
216198
}
217199

218200
unsigned int EventBlocks::broadcastByIndex(VirtualMachine *vm)
219201
{
220-
vm->engine()->broadcast(vm->getInput(0, 1)->toLong());
202+
vm->engine()->broadcast(vm->getInput(0, 1)->toLong(), vm);
221203
return 1;
222204
}
223205

@@ -226,40 +208,10 @@ unsigned int EventBlocks::broadcastAndWait(VirtualMachine *vm)
226208
std::vector<int> broadcasts = vm->engine()->findBroadcasts(vm->getInput(0, 1)->toString());
227209

228210
for (int index : broadcasts)
229-
vm->engine()->broadcast(index);
230-
231-
return 1;
232-
}
211+
vm->engine()->broadcast(index, vm);
233212

234-
unsigned int EventBlocks::broadcastByIndexAndWait(VirtualMachine *vm)
235-
{
236-
vm->engine()->broadcast(vm->getInput(0, 1)->toLong());
237-
return 1;
238-
}
239-
240-
unsigned int EventBlocks::checkBroadcast(VirtualMachine *vm)
241-
{
242-
bool running = false;
243-
244-
std::vector<int> broadcasts = vm->engine()->findBroadcasts(vm->getInput(0, 1)->toString());
213+
vm->promise();
245214

246-
for (int index : broadcasts) {
247-
if (vm->engine()->broadcastRunning(index)) {
248-
running = true;
249-
break;
250-
}
251-
}
252-
253-
if (running)
254-
vm->stop(true, true, true);
255-
256-
return 1;
257-
}
258-
259-
unsigned int EventBlocks::checkBroadcastByIndex(VirtualMachine *vm)
260-
{
261-
if (vm->engine()->broadcastRunning(vm->getInput(0, 1)->toLong()))
262-
vm->stop(true, true, true);
263215
return 1;
264216
}
265217

src/blocks/eventblocks.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,6 @@ class EventBlocks : public IBlockSection
5858
static unsigned int broadcast(VirtualMachine *vm);
5959
static unsigned int broadcastByIndex(VirtualMachine *vm);
6060
static unsigned int broadcastAndWait(VirtualMachine *vm);
61-
static unsigned int broadcastByIndexAndWait(VirtualMachine *vm);
62-
static unsigned int checkBroadcast(VirtualMachine *vm);
63-
static unsigned int checkBroadcastByIndex(VirtualMachine *vm);
6461

6562
static unsigned int whenLoudnessGreaterThanPredicate(VirtualMachine *vm);
6663
static unsigned int whenTimerGreaterThanPredicate(VirtualMachine *vm);

src/blocks/looksblocks.cpp

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -366,8 +366,6 @@ void LooksBlocks::compileSwitchBackdropToAndWait(Compiler *compiler)
366366
{
367367
compiler->addInput(BACKDROP);
368368
compiler->addFunctionCall(&switchBackdropToAndWait);
369-
compiler->addFunctionCall(&backdropNumber);
370-
compiler->addFunctionCall(&checkBackdropScripts);
371369
}
372370

373371
void LooksBlocks::compileNextBackdrop(Compiler *compiler)
@@ -894,7 +892,7 @@ void LooksBlocks::startBackdropScripts(VirtualMachine *vm, bool wait)
894892
{
895893
if (Stage *stage = vm->engine()->stage()) {
896894
if (stage->costumes().size() > 0)
897-
vm->engine()->startBackdropScripts(stage->currentCostume()->broadcast());
895+
vm->engine()->startBackdropScripts(stage->currentCostume()->broadcast(), vm);
898896
}
899897
}
900898

@@ -976,6 +974,7 @@ unsigned int LooksBlocks::switchBackdropToAndWait(VirtualMachine *vm)
976974
{
977975
switchBackdropToImpl(vm);
978976
startBackdropScripts(vm, true);
977+
vm->promise();
979978

980979
return 1;
981980
}
@@ -1004,19 +1003,6 @@ unsigned int LooksBlocks::randomBackdrop(VirtualMachine *vm)
10041003
return 0;
10051004
}
10061005

1007-
unsigned int LooksBlocks::checkBackdropScripts(VirtualMachine *vm)
1008-
{
1009-
if (Stage *stage = vm->engine()->stage()) {
1010-
long index = vm->getInput(0, 1)->toLong() - 1;
1011-
assert(stage->costumes().size() == 0 || index >= 0);
1012-
1013-
if ((stage->costumes().size() > 0) && vm->engine()->broadcastByPtrRunning(stage->costumeAt(index)->broadcast()))
1014-
vm->stop(true, true, true);
1015-
}
1016-
1017-
return 1;
1018-
}
1019-
10201006
unsigned int LooksBlocks::goToFront(VirtualMachine *vm)
10211007
{
10221008
Sprite *sprite = dynamic_cast<Sprite *>(vm->target());

src/blocks/looksblocks.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,6 @@ class LooksBlocks : public IBlockSection
144144
static unsigned int nextBackdrop(VirtualMachine *vm);
145145
static unsigned int previousBackdrop(VirtualMachine *vm);
146146
static unsigned int randomBackdrop(VirtualMachine *vm);
147-
static unsigned int checkBackdropScripts(VirtualMachine *vm);
148147

149148
static unsigned int goToFront(VirtualMachine *vm);
150149
static unsigned int goToBack(VirtualMachine *vm);

src/engine/internal/engine.cpp

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -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

454456
void 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+
18991956
std::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

src/engine/internal/engine.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@ class Engine : public IEngine
3535
void start() override;
3636
void stop() override;
3737
VirtualMachine *startScript(std::shared_ptr<Block> topLevelBlock, Target *target) override;
38-
void broadcast(int index) override;
39-
void broadcastByPtr(Broadcast *broadcast) override;
40-
void startBackdropScripts(Broadcast *broadcast) override;
38+
void broadcast(int index, VirtualMachine *sender) override;
39+
void broadcastByPtr(Broadcast *broadcast, VirtualMachine *sender) override;
40+
void startBackdropScripts(Broadcast *broadcast, VirtualMachine *sender) override;
4141
void stopScript(VirtualMachine *vm) override;
4242
void stopTarget(Target *target, VirtualMachine *exceptScript) override;
4343
void initClone(std::shared_ptr<Sprite> clone) override;
@@ -220,6 +220,8 @@ class Engine : public IEngine
220220
void updateFrameDuration();
221221
void addRunningScript(std::shared_ptr<VirtualMachine> vm);
222222

223+
void addBroadcastPromise(Broadcast *broadcast, VirtualMachine *sender);
224+
223225
std::shared_ptr<VirtualMachine> pushThread(std::shared_ptr<Block> block, Target *target);
224226
void stopThread(VirtualMachine *thread);
225227
std::shared_ptr<VirtualMachine> restartThread(std::shared_ptr<VirtualMachine> thread);
@@ -238,6 +240,7 @@ class Engine : public IEngine
238240
std::vector<std::shared_ptr<Broadcast>> m_broadcasts;
239241
std::unordered_map<Broadcast *, std::vector<Script *>> m_broadcastMap;
240242
std::unordered_map<Broadcast *, std::vector<Script *>> m_backdropBroadcastMap;
243+
std::unordered_map<Broadcast *, VirtualMachine *> m_broadcastSenders; // used for resolving broadcast promises
241244
std::vector<std::shared_ptr<Monitor>> m_monitors;
242245
std::vector<std::string> m_extensions;
243246
std::vector<Target *> m_executableTargets; // sorted by layer (reverse order of execution)

0 commit comments

Comments
 (0)