Skip to content

Commit 87a3db9

Browse files
committed
Move concrete field IDs out of Engine
1 parent 706254a commit 87a3db9

File tree

6 files changed

+86
-38
lines changed

6 files changed

+86
-38
lines changed

include/scratchcpp/iengine.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -249,16 +249,16 @@ class LIBSCRATCHCPP_EXPORT IEngine
249249
virtual void addGreenFlagScript(std::shared_ptr<Block> hatBlock) = 0;
250250

251251
/*! Registers the broadcast script. */
252-
virtual void addBroadcastScript(std::shared_ptr<Block> whenReceivedBlock, Broadcast *broadcast) = 0;
252+
virtual void addBroadcastScript(std::shared_ptr<Block> whenReceivedBlock, int fieldId, Broadcast *broadcast) = 0;
253253

254254
/*! Registers the backdrop change script. */
255-
virtual void addBackdropChangeScript(std::shared_ptr<Block> hatBlock) = 0;
255+
virtual void addBackdropChangeScript(std::shared_ptr<Block> hatBlock, int fieldId) = 0;
256256

257257
/* Registers the given "when I start as clone" script. */
258258
virtual void addCloneInitScript(std::shared_ptr<Block> hatBlock) = 0;
259259

260260
/* Registers the given "when key pressed" script. */
261-
virtual void addKeyPressScript(std::shared_ptr<Block> hatBlock) = 0;
261+
virtual void addKeyPressScript(std::shared_ptr<Block> hatBlock, int fieldId) = 0;
262262

263263
/*! Returns the list of targets. */
264264
virtual const std::vector<std::shared_ptr<Target>> &targets() const = 0;

src/blocks/eventblocks.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,18 +77,18 @@ void EventBlocks::compileWhenBroadcastReceived(Compiler *compiler)
7777
{
7878
auto broadcast = std::static_pointer_cast<Broadcast>(compiler->field(BROADCAST_OPTION)->valuePtr());
7979

80-
compiler->engine()->addBroadcastScript(compiler->block(), broadcast.get());
80+
compiler->engine()->addBroadcastScript(compiler->block(), BROADCAST_OPTION, broadcast.get());
8181
}
8282

8383
void EventBlocks::compileWhenBackdropSwitchesTo(Compiler *compiler)
8484
{
85-
compiler->engine()->addBackdropChangeScript(compiler->block());
85+
compiler->engine()->addBackdropChangeScript(compiler->block(), BACKDROP);
8686
}
8787

8888
void EventBlocks::compileWhenKeyPressed(Compiler *compiler)
8989
{
9090
// NOTE: Field values don't have to be registered because keys are referenced by their names
91-
compiler->engine()->addKeyPressScript(compiler->block());
91+
compiler->engine()->addKeyPressScript(compiler->block(), KEY_OPTION);
9292
}
9393

9494
unsigned int EventBlocks::broadcast(VirtualMachine *vm)

src/engine/internal/engine.cpp

Lines changed: 59 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
#include "timer.h"
2525
#include "clock.h"
2626
#include "blocks/standardblocks.h"
27-
#include "blocks/eventblocks.h"
2827

2928
using namespace libscratchcpp;
3029

@@ -205,12 +204,12 @@ void Engine::broadcast(unsigned int index)
205204

206205
void Engine::broadcastByPtr(Broadcast *broadcast)
207206
{
208-
startHats(HatType::BroadcastReceived, { { EventBlocks::Fields::BROADCAST_OPTION, broadcast->name() } }, nullptr);
207+
startHats(HatType::BroadcastReceived, { { HatField::BroadcastOption, broadcast->name() } }, nullptr);
209208
}
210209

211210
void Engine::startBackdropScripts(Broadcast *broadcast)
212211
{
213-
startHats(HatType::BackdropChanged, { { EventBlocks::Fields::BACKDROP, broadcast->name() } }, nullptr);
212+
startHats(HatType::BackdropChanged, { { HatField::Backdrop, broadcast->name() } }, nullptr);
214213
}
215214

216215
void Engine::stopScript(VirtualMachine *vm)
@@ -472,8 +471,8 @@ void Engine::setKeyState(const KeyEvent &event, bool pressed)
472471

473472
// Start "when key pressed" scripts
474473
if (pressed) {
475-
startHats(HatType::KeyPressed, { { EventBlocks::Fields::KEY_OPTION, event.name() } }, nullptr);
476-
startHats(HatType::KeyPressed, { { EventBlocks::Fields::KEY_OPTION, "any" } }, nullptr);
474+
startHats(HatType::KeyPressed, { { HatField::KeyOption, event.name() } }, nullptr);
475+
startHats(HatType::KeyPressed, { { HatField::KeyOption, "any" } }, nullptr);
477476
}
478477
}
479478

@@ -483,7 +482,7 @@ void Engine::setAnyKeyPressed(bool pressed)
483482

484483
// Start "when key pressed" scripts
485484
if (pressed)
486-
startHats(HatType::KeyPressed, { { EventBlocks::Fields::KEY_OPTION, "any" } }, nullptr);
485+
startHats(HatType::KeyPressed, { { HatField::KeyOption, "any" } }, nullptr);
487486
}
488487

489488
double Engine::mouseX() const
@@ -590,9 +589,17 @@ bool Engine::broadcastByPtrRunning(Broadcast *broadcast)
590589

591590
const auto &scripts = m_backdropChangeHats[script->target()];
592591
auto scriptIt = std::find(scripts.begin(), scripts.end(), script);
592+
auto scriptFieldMapIt = m_scriptHatFields.find(script);
593593

594-
if ((scriptIt != scripts.end()) && (topBlock->findFieldById(EventBlocks::BACKDROP)->value().toString() == broadcast->name()))
595-
return true;
594+
if (scriptFieldMapIt != m_scriptHatFields.cend()) {
595+
const auto &fieldMap = scriptFieldMapIt->second;
596+
auto fieldIt = fieldMap.find(HatField::Backdrop);
597+
assert(fieldIt != fieldMap.cend());
598+
assert(topBlock->findFieldById(fieldIt->second));
599+
600+
if ((scriptIt != scripts.end()) && (topBlock->findFieldById(fieldIt->second)->value().toString() == broadcast->name()))
601+
return true;
602+
}
596603
}
597604
}
598605
} else {
@@ -744,7 +751,7 @@ void Engine::addGreenFlagScript(std::shared_ptr<Block> hatBlock)
744751
addHatToMap(m_greenFlagHats, m_scripts[hatBlock].get());
745752
}
746753

747-
void Engine::addBroadcastScript(std::shared_ptr<Block> whenReceivedBlock, Broadcast *broadcast)
754+
void Engine::addBroadcastScript(std::shared_ptr<Block> whenReceivedBlock, int fieldId, Broadcast *broadcast)
748755
{
749756
assert(!broadcast->isBackdropBroadcast());
750757
Script *script = m_scripts[whenReceivedBlock].get();
@@ -760,21 +767,26 @@ void Engine::addBroadcastScript(std::shared_ptr<Block> whenReceivedBlock, Broadc
760767
m_broadcastMap[broadcast] = { script };
761768

762769
addHatToMap(m_broadcastHats, script);
770+
addHatField(script, HatField::BroadcastOption, fieldId);
763771
}
764772

765-
void Engine::addBackdropChangeScript(std::shared_ptr<Block> hatBlock)
773+
void Engine::addBackdropChangeScript(std::shared_ptr<Block> hatBlock, int fieldId)
766774
{
767-
addHatToMap(m_backdropChangeHats, m_scripts[hatBlock].get());
775+
Script *script = m_scripts[hatBlock].get();
776+
addHatToMap(m_backdropChangeHats, script);
777+
addHatField(script, HatField::Backdrop, fieldId);
768778
}
769779

770780
void Engine::addCloneInitScript(std::shared_ptr<Block> hatBlock)
771781
{
772782
addHatToMap(m_cloneInitHats, m_scripts[hatBlock].get());
773783
}
774784

775-
void Engine::addKeyPressScript(std::shared_ptr<Block> hatBlock)
785+
void Engine::addKeyPressScript(std::shared_ptr<Block> hatBlock, int fieldId)
776786
{
777-
addHatToMap(m_whenKeyPressedHats, m_scripts[hatBlock].get());
787+
Script *script = m_scripts[hatBlock].get();
788+
addHatToMap(m_whenKeyPressedHats, script);
789+
addHatField(script, HatField::KeyOption, fieldId);
778790
}
779791

780792
const std::vector<std::shared_ptr<Target>> &Engine::targets() const
@@ -1086,6 +1098,18 @@ void Engine::addHatToMap(std::unordered_map<Target *, std::vector<Script *>> &ma
10861098
map[target] = { script };
10871099
}
10881100

1101+
void Engine::addHatField(Script *script, HatField field, int fieldId)
1102+
{
1103+
auto it = m_scriptHatFields.find(script);
1104+
1105+
if (it == m_scriptHatFields.cend())
1106+
m_scriptHatFields[script] = { { field, fieldId } };
1107+
else {
1108+
auto &fieldMap = it->second;
1109+
fieldMap[field] = fieldId;
1110+
}
1111+
}
1112+
10891113
const std::vector<Script *> &Engine::getHats(Target *target, HatType type)
10901114
{
10911115
assert(target);
@@ -1269,7 +1293,7 @@ void Engine::allScriptsByOpcodeDo(HatType hatType, F &&f, Target *optTarget)
12691293
delete targetsPtr;
12701294
}
12711295

1272-
std::vector<std::shared_ptr<VirtualMachine>> Engine::startHats(HatType hatType, const std::unordered_map<int, std::string> &optMatchFields, Target *optTarget)
1296+
std::vector<std::shared_ptr<VirtualMachine>> Engine::startHats(HatType hatType, const std::unordered_map<HatField, std::string> &optMatchFields, Target *optTarget)
12731297
{
12741298
// https://github.com/scratchfoundation/scratch-vm/blob/f1aa92fad79af17d9dd1c41eeeadca099339a9f1/src/engine/runtime.js#L1818-L1889
12751299
std::vector<std::shared_ptr<VirtualMachine>> newThreads;
@@ -1282,14 +1306,28 @@ std::vector<std::shared_ptr<VirtualMachine>> Engine::startHats(HatType hatType,
12821306
assert(it != m_scripts.end());
12831307
auto topBlock = it->first;
12841308

1285-
// Match any requested fields
1286-
for (const auto &[fieldId, fieldValue] : optMatchFields) {
1287-
assert(fieldId > -1);
1288-
assert(topBlock->findFieldById(fieldId));
1309+
if (!optMatchFields.empty()) {
1310+
// Get the field map for this script
1311+
auto fieldMapIt = m_scriptHatFields.find(script);
1312+
assert(fieldMapIt != m_scriptHatFields.cend());
1313+
1314+
if (fieldMapIt != m_scriptHatFields.cend()) {
1315+
const auto &fieldMap = fieldMapIt->second;
12891316

1290-
if (topBlock->findFieldById(fieldId)->value().toString() != fieldValue) {
1291-
// Field mismatch
1292-
return;
1317+
// Match any requested fields
1318+
for (const auto &[fieldId, fieldValue] : optMatchFields) {
1319+
auto fieldIt = fieldMap.find(fieldId);
1320+
assert(fieldIt != fieldMap.cend());
1321+
1322+
if (fieldIt != fieldMap.cend()) {
1323+
assert(topBlock->findFieldById(fieldIt->second));
1324+
1325+
if (topBlock->findFieldById(fieldIt->second)->value().toString() != fieldValue) {
1326+
// Field mismatch
1327+
return;
1328+
}
1329+
}
1330+
}
12931331
}
12941332
}
12951333

src/engine/internal/engine.h

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,10 @@ class Engine : public IEngine
110110
int findBroadcastById(const std::string &broadcastId) const override;
111111

112112
void addGreenFlagScript(std::shared_ptr<Block> hatBlock) override;
113-
void addBroadcastScript(std::shared_ptr<Block> whenReceivedBlock, Broadcast *broadcast) override;
114-
void addBackdropChangeScript(std::shared_ptr<Block> hatBlock) override;
113+
void addBroadcastScript(std::shared_ptr<Block> whenReceivedBlock, int fieldId, Broadcast *broadcast) override;
114+
void addBackdropChangeScript(std::shared_ptr<Block> hatBlock, int fieldId) override;
115115
void addCloneInitScript(std::shared_ptr<Block> hatBlock) override;
116-
void addKeyPressScript(std::shared_ptr<Block> hatBlock) override;
116+
void addKeyPressScript(std::shared_ptr<Block> hatBlock, int fieldId) override;
117117

118118
const std::vector<std::shared_ptr<Target>> &targets() const override;
119119
void setTargets(const std::vector<std::shared_ptr<Target>> &newTargets) override;
@@ -148,6 +148,13 @@ class Engine : public IEngine
148148
KeyPressed
149149
};
150150

151+
enum class HatField
152+
{
153+
BroadcastOption,
154+
Backdrop,
155+
KeyOption
156+
};
157+
151158
void step();
152159
std::vector<std::shared_ptr<VirtualMachine>> stepThreads();
153160
void stepThread(std::shared_ptr<VirtualMachine> thread);
@@ -164,6 +171,7 @@ class Engine : public IEngine
164171
std::shared_ptr<IBlockSection> blockSection(const std::string &opcode) const;
165172

166173
void addHatToMap(std::unordered_map<Target *, std::vector<Script *>> &map, Script *script);
174+
void addHatField(Script *script, HatField field, int fieldId);
167175
const std::vector<libscratchcpp::Script *> &getHats(Target *target, HatType type);
168176

169177
void updateSpriteLayerOrder();
@@ -178,7 +186,7 @@ class Engine : public IEngine
178186
template<typename F>
179187
void allScriptsByOpcodeDo(HatType hatType, F &&f, Target *optTarget);
180188

181-
std::vector<std::shared_ptr<VirtualMachine>> startHats(HatType hatType, const std::unordered_map<int, std::string> &optMatchFields, Target *optTarget);
189+
std::vector<std::shared_ptr<VirtualMachine>> startHats(HatType hatType, const std::unordered_map<HatField, std::string> &optMatchFields, Target *optTarget);
182190

183191
static const std::unordered_map<HatType, bool> m_hatRestartExistingThreads; // used to check whether a hat should restart existing threads
184192

@@ -201,6 +209,8 @@ class Engine : public IEngine
201209
std::unordered_map<Target *, std::vector<Script *>> m_cloneInitHats;
202210
std::unordered_map<Target *, std::vector<Script *>> m_whenKeyPressedHats;
203211

212+
std::unordered_map<Script *, std::unordered_map<HatField, int>> m_scriptHatFields; // HatField, field ID from the block implementation
213+
204214
std::unique_ptr<ITimer> m_defaultTimer;
205215
ITimer *m_timer = nullptr;
206216
double m_fps = 30; // default FPS

test/blocks/event_blocks_test.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ TEST_F(EventBlocksTest, WhenBroadcastReceived)
285285
auto block1 = createEventBlock("a", "event_whenbroadcastreceived");
286286
addBroadcastField(block1, "BROADCAST_OPTION", EventBlocks::BROADCAST_OPTION, m_broadcast);
287287

288-
EXPECT_CALL(m_engineMock, addBroadcastScript(block1, m_broadcast.get())).Times(1);
288+
EXPECT_CALL(m_engineMock, addBroadcastScript(block1, EventBlocks::BROADCAST_OPTION, m_broadcast.get())).Times(1);
289289

290290
compiler.init();
291291
compiler.setBlock(block1);
@@ -310,7 +310,7 @@ TEST_F(EventBlocksTest, WhenBackdropSwitchesTo)
310310
auto backdrop = std::make_shared<Costume>("backdrop2", "a", "svg");
311311
stage.addCostume(backdrop);
312312

313-
EXPECT_CALL(m_engineMock, addBackdropChangeScript(block1));
313+
EXPECT_CALL(m_engineMock, addBackdropChangeScript(block1, EventBlocks::BACKDROP));
314314

315315
compiler.init();
316316
compiler.setBlock(block1);
@@ -337,11 +337,11 @@ TEST_F(EventBlocksTest, WhenKeyPressed)
337337

338338
compiler.init();
339339

340-
EXPECT_CALL(m_engineMock, addKeyPressScript(block1));
340+
EXPECT_CALL(m_engineMock, addKeyPressScript(block1, EventBlocks::KEY_OPTION));
341341
compiler.setBlock(block1);
342342
EventBlocks::compileWhenKeyPressed(&compiler);
343343

344-
EXPECT_CALL(m_engineMock, addKeyPressScript(block2));
344+
EXPECT_CALL(m_engineMock, addKeyPressScript(block2, EventBlocks::KEY_OPTION));
345345
compiler.setBlock(block2);
346346
EventBlocks::compileWhenKeyPressed(&compiler);
347347

test/mocks/enginemock.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,10 @@ class EngineMock : public IEngine
9292
MOCK_METHOD(int, findBroadcastById, (const std::string &), (const, override));
9393

9494
MOCK_METHOD(void, addGreenFlagScript, (std::shared_ptr<Block>), (override));
95-
MOCK_METHOD(void, addBroadcastScript, (std::shared_ptr<Block>, Broadcast *), (override));
96-
MOCK_METHOD(void, addBackdropChangeScript, (std::shared_ptr<Block>), (override));
95+
MOCK_METHOD(void, addBroadcastScript, (std::shared_ptr<Block>, int, Broadcast *), (override));
96+
MOCK_METHOD(void, addBackdropChangeScript, (std::shared_ptr<Block>, int), (override));
9797
MOCK_METHOD(void, addCloneInitScript, (std::shared_ptr<Block>), (override));
98-
MOCK_METHOD(void, addKeyPressScript, (std::shared_ptr<Block>), (override));
98+
MOCK_METHOD(void, addKeyPressScript, (std::shared_ptr<Block>, int), (override));
9999

100100
MOCK_METHOD(const std::vector<std::shared_ptr<Target>> &, targets, (), (const, override));
101101
MOCK_METHOD(void, setTargets, (const std::vector<std::shared_ptr<Target>> &), (override));

0 commit comments

Comments
 (0)