Skip to content

Commit 938396c

Browse files
authored
Merge pull request #562 from scratchcpp/broadcast_fixes
Broadcast fixes
2 parents 8232540 + 57967f2 commit 938396c

File tree

7 files changed

+97
-53
lines changed

7 files changed

+97
-53
lines changed

include/scratchcpp/iengine.h

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

6262
/*! Starts the scripts of the broadcast with the given index. */
63-
virtual void broadcast(unsigned int index) = 0;
63+
virtual void broadcast(int index) = 0;
6464

6565
/*! Starts the scripts of the given broadcast. */
6666
virtual void broadcastByPtr(Broadcast *broadcast) = 0;
@@ -291,8 +291,8 @@ class LIBSCRATCHCPP_EXPORT IEngine
291291
/*! Returns the broadcast at index. */
292292
virtual std::shared_ptr<Broadcast> broadcastAt(int index) const = 0;
293293

294-
/*! Returns the index of the broadcast with the given name. */
295-
virtual int findBroadcast(const std::string &broadcastName) const = 0;
294+
/*! Returns the list of indexes of the broadcasts with the given name (case insensitive). */
295+
virtual std::vector<int> findBroadcasts(const std::string &broadcastName) const = 0;
296296

297297
/*! Returns the index of the broadcast with the given ID. */
298298
virtual int findBroadcastById(const std::string &broadcastId) const = 0;

src/blocks/eventblocks.cpp

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,12 @@ void EventBlocks::compileBroadcast(Compiler *compiler)
9999
auto input = compiler->input(BROADCAST_INPUT);
100100

101101
if (input->type() != Input::Type::ObscuredShadow) {
102-
compiler->addConstValue(compiler->engine()->findBroadcast(input->primaryValue()->value().toString()));
103-
compiler->addFunctionCall(&broadcastByIndex);
102+
std::vector<int> broadcasts = compiler->engine()->findBroadcasts(input->primaryValue()->value().toString());
103+
104+
for (int index : broadcasts) {
105+
compiler->addConstValue(index);
106+
compiler->addFunctionCall(&broadcastByIndex);
107+
}
104108
} else {
105109
compiler->addInput(input);
106110
compiler->addFunctionCall(&broadcast);
@@ -112,11 +116,17 @@ void EventBlocks::compileBroadcastAndWait(Compiler *compiler)
112116
auto input = compiler->input(BROADCAST_INPUT);
113117

114118
if (input->type() != Input::Type::ObscuredShadow) {
115-
int index = compiler->engine()->findBroadcast(input->primaryValue()->value().toString());
116-
compiler->addConstValue(index);
117-
compiler->addFunctionCall(&broadcastByIndexAndWait);
118-
compiler->addConstValue(index);
119-
compiler->addFunctionCall(&checkBroadcastByIndex);
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+
}
120130
} else {
121131
compiler->addInput(input);
122132
compiler->addFunctionCall(&broadcastAndWait);
@@ -197,7 +207,11 @@ unsigned int EventBlocks::whenTouchingObjectPredicate(VirtualMachine *vm)
197207

198208
unsigned int EventBlocks::broadcast(VirtualMachine *vm)
199209
{
200-
vm->engine()->broadcast(vm->engine()->findBroadcast(vm->getInput(0, 1)->toString()));
210+
std::vector<int> broadcasts = vm->engine()->findBroadcasts(vm->getInput(0, 1)->toString());
211+
212+
for (int index : broadcasts)
213+
vm->engine()->broadcast(index);
214+
201215
return 1;
202216
}
203217

@@ -209,7 +223,11 @@ unsigned int EventBlocks::broadcastByIndex(VirtualMachine *vm)
209223

210224
unsigned int EventBlocks::broadcastAndWait(VirtualMachine *vm)
211225
{
212-
vm->engine()->broadcast(vm->engine()->findBroadcast(vm->getInput(0, 1)->toString()));
226+
std::vector<int> broadcasts = vm->engine()->findBroadcasts(vm->getInput(0, 1)->toString());
227+
228+
for (int index : broadcasts)
229+
vm->engine()->broadcast(index);
230+
213231
return 1;
214232
}
215233

@@ -221,8 +239,20 @@ unsigned int EventBlocks::broadcastByIndexAndWait(VirtualMachine *vm)
221239

222240
unsigned int EventBlocks::checkBroadcast(VirtualMachine *vm)
223241
{
224-
if (vm->engine()->broadcastRunning(vm->engine()->findBroadcast(vm->getInput(0, 1)->toString())))
242+
bool running = false;
243+
244+
std::vector<int> broadcasts = vm->engine()->findBroadcasts(vm->getInput(0, 1)->toString());
245+
246+
for (int index : broadcasts) {
247+
if (vm->engine()->broadcastRunning(index)) {
248+
running = true;
249+
break;
250+
}
251+
}
252+
253+
if (running)
225254
vm->stop(true, true, true);
255+
226256
return 1;
227257
}
228258

src/engine/internal/engine.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,7 @@ VirtualMachine *Engine::startScript(std::shared_ptr<Block> topLevelBlock, Target
415415
return pushThread(topLevelBlock, target).get();
416416
}
417417

418-
void Engine::broadcast(unsigned int index)
418+
void Engine::broadcast(int index)
419419
{
420420
if (index < 0 || index >= m_broadcasts.size())
421421
return;
@@ -1081,21 +1081,21 @@ std::shared_ptr<Broadcast> Engine::broadcastAt(int index) const
10811081
return m_broadcasts[index];
10821082
}
10831083

1084-
int Engine::findBroadcast(const std::string &broadcastName) const
1084+
std::vector<int> Engine::findBroadcasts(const std::string &broadcastName) const
10851085
{
1086+
std::vector<int> ret;
10861087
std::string lowercaseName = broadcastName;
10871088
std::transform(lowercaseName.begin(), lowercaseName.end(), lowercaseName.begin(), ::tolower);
10881089

1089-
auto it = std::find_if(m_broadcasts.begin(), m_broadcasts.end(), [lowercaseName](std::shared_ptr<Broadcast> broadcast) {
1090-
std::string name = broadcast->name();
1090+
for (unsigned int i = 0; i < m_broadcasts.size(); i++) {
1091+
std::string name = m_broadcasts[i]->name();
10911092
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
1092-
return name == lowercaseName;
1093-
});
10941093

1095-
if (it == m_broadcasts.end())
1096-
return -1;
1097-
else
1098-
return it - m_broadcasts.begin();
1094+
if (name == lowercaseName)
1095+
ret.push_back(i);
1096+
}
1097+
1098+
return ret;
10991099
}
11001100

11011101
int Engine::findBroadcastById(const std::string &broadcastId) const

src/engine/internal/engine.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ 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(unsigned int index) override;
38+
void broadcast(int index) override;
3939
void broadcastByPtr(Broadcast *broadcast) override;
4040
void startBackdropScripts(Broadcast *broadcast) override;
4141
void stopScript(VirtualMachine *vm) override;
@@ -123,7 +123,7 @@ class Engine : public IEngine
123123
const std::vector<std::shared_ptr<Broadcast>> &broadcasts() const override;
124124
void setBroadcasts(const std::vector<std::shared_ptr<Broadcast>> &broadcasts) override;
125125
std::shared_ptr<Broadcast> broadcastAt(int index) const override;
126-
int findBroadcast(const std::string &broadcastName) const override;
126+
std::vector<int> findBroadcasts(const std::string &broadcastName) const override;
127127
int findBroadcastById(const std::string &broadcastId) const override;
128128

129129
void addWhenTouchingObjectScript(std::shared_ptr<Block> hatBlock) override;

test/blocks/event_blocks_test.cpp

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -373,8 +373,8 @@ TEST_F(EventBlocksTest, Broadcast)
373373
notBlock->setCompileFunction(&OperatorBlocks::compileNot);
374374
addObscuredInput(block2, "BROADCAST_INPUT", EventBlocks::BROADCAST_INPUT, notBlock);
375375

376-
EXPECT_CALL(m_engineMock, findBroadcast("test")).WillOnce(Return(0));
377-
EXPECT_CALL(m_engineMock, functionIndex(&EventBlocks::broadcastByIndex)).WillOnce(Return(0));
376+
EXPECT_CALL(m_engineMock, findBroadcasts("test")).WillOnce(Return(std::vector<int>({ 0, 3 })));
377+
EXPECT_CALL(m_engineMock, functionIndex(&EventBlocks::broadcastByIndex)).Times(2).WillRepeatedly(Return(0));
378378
EXPECT_CALL(m_engineMock, functionIndex(&EventBlocks::broadcast)).WillOnce(Return(1));
379379

380380
compiler.init();
@@ -384,9 +384,8 @@ TEST_F(EventBlocksTest, Broadcast)
384384
EventBlocks::compileBroadcast(&compiler);
385385
compiler.end();
386386

387-
ASSERT_EQ(compiler.bytecode(), std::vector<unsigned int>({ vm::OP_START, vm::OP_CONST, 0, vm::OP_EXEC, 0, vm::OP_NULL, vm::OP_NOT, vm::OP_EXEC, 1, vm::OP_HALT }));
388-
ASSERT_EQ(compiler.constValues().size(), 1);
389-
ASSERT_EQ(compiler.constValues()[0].toDouble(), 0);
387+
ASSERT_EQ(compiler.bytecode(), std::vector<unsigned int>({ vm::OP_START, vm::OP_CONST, 0, vm::OP_EXEC, 0, vm::OP_CONST, 1, vm::OP_EXEC, 0, vm::OP_NULL, vm::OP_NOT, vm::OP_EXEC, 1, vm::OP_HALT }));
388+
ASSERT_EQ(compiler.constValues(), std::vector<Value>({ 0, 3 }));
390389
ASSERT_TRUE(compiler.variables().empty());
391390
ASSERT_TRUE(compiler.lists().empty());
392391
}
@@ -402,8 +401,9 @@ TEST_F(EventBlocksTest, BroadcastImpl)
402401
vm.setFunctions(functions);
403402
vm.setConstValues(constValues);
404403

405-
EXPECT_CALL(m_engineMock, findBroadcast("test")).WillOnce(Return(1));
406-
EXPECT_CALL(m_engineMock, broadcast(1)).Times(1);
404+
EXPECT_CALL(m_engineMock, findBroadcasts("test")).WillOnce(Return(std::vector<int>({ 1, 4 })));
405+
EXPECT_CALL(m_engineMock, broadcast(1));
406+
EXPECT_CALL(m_engineMock, broadcast(4));
407407

408408
vm.setBytecode(bytecode1);
409409
vm.run();
@@ -432,9 +432,9 @@ TEST_F(EventBlocksTest, BroadcastAndWait)
432432
notBlock->setCompileFunction(&OperatorBlocks::compileNot);
433433
addObscuredInput(block2, "BROADCAST_INPUT", EventBlocks::BROADCAST_INPUT, notBlock);
434434

435-
EXPECT_CALL(m_engineMock, findBroadcast("test")).WillOnce(Return(0));
436-
EXPECT_CALL(m_engineMock, functionIndex(&EventBlocks::broadcastByIndexAndWait)).WillOnce(Return(0));
437-
EXPECT_CALL(m_engineMock, functionIndex(&EventBlocks::checkBroadcastByIndex)).WillOnce(Return(1));
435+
EXPECT_CALL(m_engineMock, findBroadcasts("test")).WillOnce(Return(std::vector<int>({ 0, 3 })));
436+
EXPECT_CALL(m_engineMock, functionIndex(&EventBlocks::broadcastByIndexAndWait)).Times(2).WillRepeatedly(Return(0));
437+
EXPECT_CALL(m_engineMock, functionIndex(&EventBlocks::checkBroadcastByIndex)).Times(2).WillRepeatedly(Return(1));
438438
EXPECT_CALL(m_engineMock, functionIndex(&EventBlocks::broadcastAndWait)).WillOnce(Return(2));
439439
EXPECT_CALL(m_engineMock, functionIndex(&EventBlocks::checkBroadcast)).WillOnce(Return(3));
440440

@@ -448,8 +448,9 @@ TEST_F(EventBlocksTest, BroadcastAndWait)
448448
ASSERT_EQ(
449449
compiler.bytecode(),
450450
std::vector<unsigned int>(
451-
{ vm::OP_START, vm::OP_CONST, 0, vm::OP_EXEC, 0, vm::OP_CONST, 1, vm::OP_EXEC, 1, vm::OP_NULL, vm::OP_NOT, vm::OP_EXEC, 2, vm::OP_NULL, vm::OP_NOT, vm::OP_EXEC, 3, vm::OP_HALT }));
452-
ASSERT_EQ(compiler.constValues(), std::vector<Value>({ 0, 0 }));
451+
{ vm::OP_START, vm::OP_CONST, 0, vm::OP_EXEC, 0, vm::OP_CONST, 1, vm::OP_EXEC, 0, vm::OP_CONST, 2, vm::OP_EXEC, 1, vm::OP_CONST, 3, vm::OP_EXEC, 1,
452+
vm::OP_NULL, vm::OP_NOT, vm::OP_EXEC, 2, vm::OP_NULL, vm::OP_NOT, vm::OP_EXEC, 3, vm::OP_HALT }));
453+
ASSERT_EQ(compiler.constValues(), std::vector<Value>({ 0, 3, 0, 3 }));
453454
ASSERT_TRUE(compiler.variables().empty());
454455
ASSERT_TRUE(compiler.lists().empty());
455456
}
@@ -467,15 +468,16 @@ TEST_F(EventBlocksTest, BroadcastAndWaitImpl)
467468
vm.setFunctions(functions);
468469
vm.setConstValues(constValues);
469470

470-
EXPECT_CALL(m_engineMock, findBroadcast("test")).WillOnce(Return(1));
471-
EXPECT_CALL(m_engineMock, broadcast(1)).Times(1);
471+
EXPECT_CALL(m_engineMock, findBroadcasts("test")).WillOnce(Return(std::vector<int>({ 1, 4 })));
472+
EXPECT_CALL(m_engineMock, broadcast(1));
473+
EXPECT_CALL(m_engineMock, broadcast(4));
472474

473475
vm.setBytecode(bytecode1);
474476
vm.run();
475477

476478
ASSERT_EQ(vm.registerCount(), 0);
477479

478-
EXPECT_CALL(m_engineMock, findBroadcast("test")).WillOnce(Return(2));
480+
EXPECT_CALL(m_engineMock, findBroadcasts("test")).WillOnce(Return(std::vector<int>({ 2, 3 })));
479481
EXPECT_CALL(m_engineMock, broadcastRunning(2)).WillOnce(Return(true));
480482

481483
vm.setBytecode(bytecode2);
@@ -484,8 +486,18 @@ TEST_F(EventBlocksTest, BroadcastAndWaitImpl)
484486
ASSERT_EQ(vm.registerCount(), 1);
485487
ASSERT_EQ(vm.atEnd(), false);
486488

487-
EXPECT_CALL(m_engineMock, findBroadcast("test")).WillOnce(Return(2));
489+
EXPECT_CALL(m_engineMock, findBroadcasts("test")).WillOnce(Return(std::vector<int>({ 2, 3 })));
490+
EXPECT_CALL(m_engineMock, broadcastRunning(2)).WillOnce(Return(true));
491+
492+
vm.reset();
493+
vm.run();
494+
495+
ASSERT_EQ(vm.registerCount(), 1);
496+
ASSERT_EQ(vm.atEnd(), false);
497+
498+
EXPECT_CALL(m_engineMock, findBroadcasts("test")).WillOnce(Return(std::vector<int>({ 2, 3 })));
488499
EXPECT_CALL(m_engineMock, broadcastRunning(2)).WillOnce(Return(false));
500+
EXPECT_CALL(m_engineMock, broadcastRunning(3)).WillOnce(Return(false));
489501

490502
vm.run();
491503

test/engine/engine_test.cpp

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1276,23 +1276,25 @@ TEST(EngineTest, Broadcasts)
12761276
auto b1 = std::make_shared<Broadcast>("a", "message1");
12771277
auto b2 = std::make_shared<Broadcast>("b", "message2");
12781278
auto b3 = std::make_shared<Broadcast>("c", "Test");
1279-
engine.setBroadcasts({ b1, b2, b3 });
1279+
auto b4 = std::make_shared<Broadcast>("d", "TesT");
1280+
engine.setBroadcasts({ b1, b2, b3, b4 });
12801281

1281-
ASSERT_EQ(engine.broadcasts(), std::vector<std::shared_ptr<Broadcast>>({ b1, b2, b3 }));
1282+
ASSERT_EQ(engine.broadcasts(), std::vector<std::shared_ptr<Broadcast>>({ b1, b2, b3, b4 }));
12821283
ASSERT_EQ(engine.broadcastAt(0), b1);
12831284
ASSERT_EQ(engine.broadcastAt(1), b2);
12841285
ASSERT_EQ(engine.broadcastAt(2), b3);
1285-
ASSERT_EQ(engine.broadcastAt(3), nullptr);
1286+
ASSERT_EQ(engine.broadcastAt(3), b4);
1287+
ASSERT_EQ(engine.broadcastAt(4), nullptr);
12861288
ASSERT_EQ(engine.broadcastAt(-1), nullptr);
12871289

1288-
ASSERT_EQ(engine.findBroadcast("invalid"), -1);
1289-
ASSERT_EQ(engine.findBroadcast("message1"), 0);
1290-
ASSERT_EQ(engine.findBroadcast("message2"), 1);
1291-
ASSERT_EQ(engine.findBroadcast("Test"), 2);
1292-
ASSERT_EQ(engine.findBroadcast("MessAge2"), 1);
1293-
ASSERT_EQ(engine.findBroadcast("tEst"), 2);
1290+
ASSERT_TRUE(engine.findBroadcasts("invalid").empty());
1291+
ASSERT_EQ(engine.findBroadcasts("message1"), std::vector<int>({ 0 }));
1292+
ASSERT_EQ(engine.findBroadcasts("message2"), std::vector<int>({ 1 }));
1293+
ASSERT_EQ(engine.findBroadcasts("Test"), std::vector<int>({ 2, 3 }));
1294+
ASSERT_EQ(engine.findBroadcasts("MessAge2"), std::vector<int>({ 1 }));
1295+
ASSERT_EQ(engine.findBroadcasts("tEst"), std::vector<int>({ 2, 3 }));
12941296

1295-
ASSERT_EQ(engine.findBroadcastById("d"), -1);
1297+
ASSERT_EQ(engine.findBroadcastById("e"), -1);
12961298
ASSERT_EQ(engine.findBroadcastById("a"), 0);
12971299
ASSERT_EQ(engine.findBroadcastById("b"), 1);
12981300
ASSERT_EQ(engine.findBroadcastById("c"), 2);

test/mocks/enginemock.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class EngineMock : public IEngine
1717
MOCK_METHOD(void, start, (), (override));
1818
MOCK_METHOD(void, stop, (), (override));
1919
MOCK_METHOD(VirtualMachine *, startScript, (std::shared_ptr<Block>, Target *), (override));
20-
MOCK_METHOD(void, broadcast, (unsigned int), (override));
20+
MOCK_METHOD(void, broadcast, (int), (override));
2121
MOCK_METHOD(void, broadcastByPtr, (Broadcast *), (override));
2222
MOCK_METHOD(void, startBackdropScripts, (Broadcast *), (override));
2323
MOCK_METHOD(void, stopScript, (VirtualMachine *), (override));
@@ -103,7 +103,7 @@ class EngineMock : public IEngine
103103
MOCK_METHOD(const std::vector<std::shared_ptr<Broadcast>> &, broadcasts, (), (const, override));
104104
MOCK_METHOD(void, setBroadcasts, (const std::vector<std::shared_ptr<Broadcast>> &), (override));
105105
MOCK_METHOD(std::shared_ptr<Broadcast>, broadcastAt, (int), (const, override));
106-
MOCK_METHOD(int, findBroadcast, (const std::string &), (const, override));
106+
MOCK_METHOD(std::vector<int>, findBroadcasts, (const std::string &), (const, override));
107107
MOCK_METHOD(int, findBroadcastById, (const std::string &), (const, override));
108108

109109
MOCK_METHOD(void, addWhenTouchingObjectScript, (std::shared_ptr<Block>), (override));

0 commit comments

Comments
 (0)