Skip to content

Commit af49e8b

Browse files
committed
Engine: Add clone API
1 parent 76ab117 commit af49e8b

File tree

4 files changed

+63
-0
lines changed

4 files changed

+63
-0
lines changed

include/scratchcpp/iengine.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class IBlockSection;
1515
class Broadcast;
1616
class Block;
1717
class Target;
18+
class Sprite;
1819
class Script;
1920

2021
/*!
@@ -70,6 +71,9 @@ class LIBSCRATCHCPP_EXPORT IEngine
7071
*/
7172
virtual void stopTarget(Target *target, VirtualMachine *exceptScript) = 0;
7273

74+
/*! Calls the "when I start as a clone" blocks of the given sprite. */
75+
virtual void initClone(Sprite *clone) = 0;
76+
7377
/*!
7478
* Runs the event loop and calls "when green flag clicked" blocks.
7579
* \note This function returns when all scripts finish.\n
@@ -157,6 +161,9 @@ class LIBSCRATCHCPP_EXPORT IEngine
157161
/*! Registers the broadcast script. */
158162
virtual void addBroadcastScript(std::shared_ptr<Block> whenReceivedBlock, std::shared_ptr<Broadcast> broadcast) = 0;
159163

164+
/* Registers the given "when I start as clone" script. */
165+
virtual void addCloneInitScript(std::shared_ptr<Block> hatBlock) = 0;
166+
160167
/*! Returns the list of targets. */
161168
virtual const std::vector<std::shared_ptr<Target>> &targets() const = 0;
162169

src/engine/internal/engine.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
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>
@@ -258,6 +259,37 @@ void Engine::stopTarget(Target *target, VirtualMachine *exceptScript)
258259
stopScript(script);
259260
}
260261

262+
void Engine::initClone(Sprite *clone)
263+
{
264+
if (!clone)
265+
return;
266+
267+
Sprite *source = clone->cloneParent();
268+
Target *root = clone->cloneRoot();
269+
assert(source);
270+
assert(root);
271+
272+
if (!source || !root)
273+
return;
274+
275+
auto it = m_cloneInitScriptsMap.find(root);
276+
277+
if (it != m_cloneInitScriptsMap.cend()) {
278+
const auto &scripts = it->second;
279+
280+
#ifndef NDEBUG
281+
// Since we're initializing the clone, it shouldn't have any running scripts
282+
for (const auto script : m_runningScripts)
283+
assert(script->target() != clone);
284+
#endif
285+
286+
for (auto script : scripts) {
287+
auto vm = script->start(clone);
288+
m_runningScripts.push_back(vm);
289+
}
290+
}
291+
}
292+
261293
void Engine::run()
262294
{
263295
auto frameDuration = std::chrono::milliseconds(33);
@@ -442,6 +474,7 @@ void Engine::addBroadcastScript(std::shared_ptr<Block> whenReceivedBlock, std::s
442474
auto id = findBroadcast(broadcast->name());
443475
if (m_broadcastMap.count(id) == 1) {
444476
std::vector<Script *> &scripts = m_broadcastMap[id];
477+
// TODO: Do not allow adding existing scripts
445478
scripts.push_back(m_scripts[whenReceivedBlock].get());
446479
} else {
447480
m_broadcastMap[id] = { m_scripts[whenReceivedBlock].get() };
@@ -452,6 +485,22 @@ void Engine::addBroadcastScript(std::shared_ptr<Block> whenReceivedBlock, std::s
452485
}
453486
}
454487

488+
void Engine::addCloneInitScript(std::shared_ptr<Block> hatBlock)
489+
{
490+
Target *target = hatBlock->target();
491+
Script *script = m_scripts[hatBlock].get();
492+
auto it = m_cloneInitScriptsMap.find(target);
493+
494+
if (it == m_cloneInitScriptsMap.cend())
495+
m_cloneInitScriptsMap[target] = { m_scripts[hatBlock].get() };
496+
else {
497+
auto &scripts = it->second;
498+
499+
if (std::find(scripts.begin(), scripts.end(), script) == scripts.cend())
500+
scripts.push_back(script);
501+
}
502+
}
503+
455504
const std::vector<std::shared_ptr<Target>> &Engine::targets() const
456505
{
457506
return m_targets;

src/engine/internal/engine.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class Engine : public IEngine
3232
void broadcast(unsigned int index, VirtualMachine *sourceScript, bool wait = false) override;
3333
void stopScript(VirtualMachine *vm) override;
3434
void stopTarget(Target *target, VirtualMachine *exceptScript) override;
35+
void initClone(libscratchcpp::Sprite *clone) override;
3536
void run() override;
3637

3738
bool broadcastRunning(unsigned int index, VirtualMachine *sourceScript) override;
@@ -60,6 +61,8 @@ class Engine : public IEngine
6061

6162
void addBroadcastScript(std::shared_ptr<Block> whenReceivedBlock, std::shared_ptr<Broadcast> broadcast) override;
6263

64+
void addCloneInitScript(std::shared_ptr<Block> hatBlock) override;
65+
6366
const std::vector<std::shared_ptr<Target>> &targets() const override;
6467
void setTargets(const std::vector<std::shared_ptr<Target>> &newTargets) override;
6568
Target *targetAt(int index) const override;
@@ -86,6 +89,7 @@ class Engine : public IEngine
8689
std::vector<std::shared_ptr<Broadcast>> m_broadcasts;
8790
std::unordered_map<unsigned int, std::vector<Script *>> m_broadcastMap;
8891
std::unordered_map<unsigned int, std::vector<std::pair<VirtualMachine *, VirtualMachine *>>> m_runningBroadcastMap; // source script, "when received" script
92+
std::unordered_map<Target *, std::vector<Script *>> m_cloneInitScriptsMap; // target (no clones), "when I start as a clone" scripts
8993
std::vector<std::string> m_extensions;
9094
std::vector<std::shared_ptr<VirtualMachine>> m_runningScripts;
9195
std::vector<VirtualMachine *> m_scriptsToRemove;

test/mocks/enginemock.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class EngineMock : public IEngine
2121
MOCK_METHOD(void, broadcast, (unsigned int, VirtualMachine *, bool), (override));
2222
MOCK_METHOD(void, stopScript, (VirtualMachine *), (override));
2323
MOCK_METHOD(void, stopTarget, (Target *, VirtualMachine *), (override));
24+
MOCK_METHOD(void, initClone, (Sprite *), (override));
2425
MOCK_METHOD(void, run, (), (override));
2526

2627
MOCK_METHOD(bool, broadcastRunning, (unsigned int, VirtualMachine *), (override));
@@ -48,6 +49,8 @@ class EngineMock : public IEngine
4849

4950
MOCK_METHOD(void, addBroadcastScript, (std::shared_ptr<Block>, std::shared_ptr<Broadcast>), (override));
5051

52+
MOCK_METHOD(void, addCloneInitScript, (std::shared_ptr<Block>), (override));
53+
5154
MOCK_METHOD(const std::vector<std::shared_ptr<Target>> &, targets, (), (const, override));
5255
MOCK_METHOD(void, setTargets, (const std::vector<std::shared_ptr<Target>> &), (override));
5356
MOCK_METHOD(Target *, targetAt, (int), (const, override));

0 commit comments

Comments
 (0)