diff --git a/include/scratchcpp/broadcast.h b/include/scratchcpp/broadcast.h index 0aacdd56..f6e021c7 100644 --- a/include/scratchcpp/broadcast.h +++ b/include/scratchcpp/broadcast.h @@ -13,12 +13,14 @@ class BroadcastPrivate; class LIBSCRATCHCPP_EXPORT Broadcast : public Entity { public: - Broadcast(const std::string &id, const std::string &name); + Broadcast(const std::string &id, const std::string &name, bool isBackdropBroadcast = false); Broadcast(const Broadcast &) = delete; const std::string &name() const; void setName(const std::string &newName); + bool isBackdropBroadcast() const; + private: spimpl::unique_impl_ptr impl; }; diff --git a/include/scratchcpp/iengine.h b/include/scratchcpp/iengine.h index 7306a2c5..4bb0a045 100644 --- a/include/scratchcpp/iengine.h +++ b/include/scratchcpp/iengine.h @@ -56,11 +56,14 @@ class LIBSCRATCHCPP_EXPORT IEngine /*! Starts a script with the given top level block as the given Target (a sprite or the stage). */ virtual VirtualMachine *startScript(std::shared_ptr topLevelBlock, Target *) = 0; - /*! Starts the script of the broadcast with the given index. */ - virtual void broadcast(unsigned int index, VirtualMachine *sourceScript, bool wait = false) = 0; + /*! Starts the scripts of the broadcast with the given index. */ + virtual void broadcast(unsigned int index) = 0; - /*! Starts the script of the given broadcast. */ - virtual void broadcastByPtr(Broadcast *broadcast, VirtualMachine *sourceScript, bool wait = false) = 0; + /*! Starts the scripts of the given broadcast. */ + virtual void broadcastByPtr(Broadcast *broadcast) = 0; + + /*! Starts the "when backdrop switches to" scripts for the given backdrop broadcast. */ + virtual void startBackdropScripts(Broadcast *broadcast) = 0; /*! Stops the given script. */ virtual void stopScript(VirtualMachine *vm) = 0; @@ -174,10 +177,10 @@ class LIBSCRATCHCPP_EXPORT IEngine virtual void setSpriteFencingEnabled(bool enable) = 0; /*! Returns true if there are any running script of the broadcast with the given index. */ - virtual bool broadcastRunning(unsigned int index, VirtualMachine *sourceScript) = 0; + virtual bool broadcastRunning(unsigned int index) = 0; /*! Returns true if there are any running script of the given broadcast. */ - virtual bool broadcastByPtrRunning(Broadcast *broadcast, VirtualMachine *sourceScript) = 0; + virtual bool broadcastByPtrRunning(Broadcast *broadcast) = 0; /*! * Call this from a block implementation to force a redraw (screen refresh). @@ -242,14 +245,20 @@ class LIBSCRATCHCPP_EXPORT IEngine /*! Returns the index of the broadcast with the given ID. */ virtual int findBroadcastById(const std::string &broadcastId) const = 0; + /*! Registers the "green flag" script. */ + virtual void addGreenFlagScript(std::shared_ptr hatBlock) = 0; + /*! Registers the broadcast script. */ - virtual void addBroadcastScript(std::shared_ptr whenReceivedBlock, Broadcast *broadcast) = 0; + virtual void addBroadcastScript(std::shared_ptr whenReceivedBlock, int fieldId, Broadcast *broadcast) = 0; + + /*! Registers the backdrop change script. */ + virtual void addBackdropChangeScript(std::shared_ptr hatBlock, int fieldId) = 0; /* Registers the given "when I start as clone" script. */ virtual void addCloneInitScript(std::shared_ptr hatBlock) = 0; /* Registers the given "when key pressed" script. */ - virtual void addKeyPressScript(std::shared_ptr hatBlock, std::string keyName) = 0; + virtual void addKeyPressScript(std::shared_ptr hatBlock, int fieldId) = 0; /*! Returns the list of targets. */ virtual const std::vector> &targets() const = 0; diff --git a/include/scratchcpp/script.h b/include/scratchcpp/script.h index 78afd2d4..bd80c86e 100644 --- a/include/scratchcpp/script.h +++ b/include/scratchcpp/script.h @@ -12,6 +12,7 @@ namespace libscratchcpp { class Target; +class Block; class IEngine; class Value; class VirtualMachine; @@ -23,10 +24,11 @@ class ScriptPrivate; class LIBSCRATCHCPP_EXPORT Script { public: - Script(Target *target, IEngine *engine); + Script(Target *target, std::shared_ptr topBlock, IEngine *engine); Script(const Script &) = delete; Target *target() const; + std::shared_ptr topBlock() const; unsigned int *bytecode() const; const std::vector &bytecodeVector() const; diff --git a/include/scratchcpp/virtualmachine.h b/include/scratchcpp/virtualmachine.h index 3789e8f5..c00a0996 100644 --- a/include/scratchcpp/virtualmachine.h +++ b/include/scratchcpp/virtualmachine.h @@ -128,6 +128,7 @@ class LIBSCRATCHCPP_EXPORT VirtualMachine void replaceReturnValue(const Value &v, unsigned int offset); void run(); + void kill(); void reset(); void moveToLastCheckpoint(); diff --git a/src/blocks/eventblocks.cpp b/src/blocks/eventblocks.cpp index 7cffe7ce..4edd07b7 100644 --- a/src/blocks/eventblocks.cpp +++ b/src/blocks/eventblocks.cpp @@ -21,7 +21,7 @@ std::string EventBlocks::name() const void EventBlocks::registerBlocks(IEngine *engine) { // Blocks - engine->addHatBlock(this, "event_whenflagclicked"); + engine->addCompileFunction(this, "event_whenflagclicked", &compileWhenFlagClicked); engine->addCompileFunction(this, "event_broadcast", &compileBroadcast); engine->addCompileFunction(this, "event_broadcastandwait", &compileBroadcastAndWait); engine->addCompileFunction(this, "event_whenbroadcastreceived", &compileWhenBroadcastReceived); @@ -37,6 +37,11 @@ void EventBlocks::registerBlocks(IEngine *engine) engine->addField(this, "KEY_OPTION", KEY_OPTION); } +void EventBlocks::compileWhenFlagClicked(Compiler *compiler) +{ + compiler->engine()->addGreenFlagScript(compiler->block()); +} + void EventBlocks::compileBroadcast(Compiler *compiler) { auto input = compiler->input(BROADCAST_INPUT); @@ -72,60 +77,54 @@ void EventBlocks::compileWhenBroadcastReceived(Compiler *compiler) { auto broadcast = std::static_pointer_cast(compiler->field(BROADCAST_OPTION)->valuePtr()); - compiler->engine()->addBroadcastScript(compiler->block(), broadcast.get()); + compiler->engine()->addBroadcastScript(compiler->block(), BROADCAST_OPTION, broadcast.get()); } void EventBlocks::compileWhenBackdropSwitchesTo(Compiler *compiler) { - if (Stage *stage = compiler->engine()->stage()) { - std::string backdropName = compiler->field(BACKDROP)->value().toString(); - int index = stage->findCostume(backdropName); - - if (index != -1) - compiler->engine()->addBroadcastScript(compiler->block(), stage->costumeAt(index)->broadcast()); - } + compiler->engine()->addBackdropChangeScript(compiler->block(), BACKDROP); } void EventBlocks::compileWhenKeyPressed(Compiler *compiler) { // NOTE: Field values don't have to be registered because keys are referenced by their names - compiler->engine()->addKeyPressScript(compiler->block(), compiler->field(KEY_OPTION)->value().toString()); + compiler->engine()->addKeyPressScript(compiler->block(), KEY_OPTION); } unsigned int EventBlocks::broadcast(VirtualMachine *vm) { - vm->engine()->broadcast(vm->engine()->findBroadcast(vm->getInput(0, 1)->toString()), vm); + vm->engine()->broadcast(vm->engine()->findBroadcast(vm->getInput(0, 1)->toString())); return 1; } unsigned int EventBlocks::broadcastByIndex(VirtualMachine *vm) { - vm->engine()->broadcast(vm->getInput(0, 1)->toLong(), vm); + vm->engine()->broadcast(vm->getInput(0, 1)->toLong()); return 1; } unsigned int EventBlocks::broadcastAndWait(VirtualMachine *vm) { - vm->engine()->broadcast(vm->engine()->findBroadcast(vm->getInput(0, 1)->toString()), vm, true); + vm->engine()->broadcast(vm->engine()->findBroadcast(vm->getInput(0, 1)->toString())); return 1; } unsigned int EventBlocks::broadcastByIndexAndWait(VirtualMachine *vm) { - vm->engine()->broadcast(vm->getInput(0, 1)->toLong(), vm, true); + vm->engine()->broadcast(vm->getInput(0, 1)->toLong()); return 1; } unsigned int EventBlocks::checkBroadcast(VirtualMachine *vm) { - if (vm->engine()->broadcastRunning(vm->engine()->findBroadcast(vm->getInput(0, 1)->toString()), vm)) + if (vm->engine()->broadcastRunning(vm->engine()->findBroadcast(vm->getInput(0, 1)->toString()))) vm->stop(true, true, true); return 1; } unsigned int EventBlocks::checkBroadcastByIndex(VirtualMachine *vm) { - if (vm->engine()->broadcastRunning(vm->getInput(0, 1)->toLong(), vm)) + if (vm->engine()->broadcastRunning(vm->getInput(0, 1)->toLong())) vm->stop(true, true, true); return 1; } diff --git a/src/blocks/eventblocks.h b/src/blocks/eventblocks.h index 5e9e4502..21f7e812 100644 --- a/src/blocks/eventblocks.h +++ b/src/blocks/eventblocks.h @@ -30,6 +30,7 @@ class EventBlocks : public IBlockSection void registerBlocks(IEngine *engine) override; + static void compileWhenFlagClicked(Compiler *compiler); static void compileBroadcast(Compiler *compiler); static void compileBroadcastAndWait(Compiler *compiler); static void compileWhenBroadcastReceived(Compiler *compiler); diff --git a/src/blocks/looksblocks.cpp b/src/blocks/looksblocks.cpp index eee69eef..ab5290c0 100644 --- a/src/blocks/looksblocks.cpp +++ b/src/blocks/looksblocks.cpp @@ -388,6 +388,7 @@ void LooksBlocks::compileSwitchBackdropToAndWait(Compiler *compiler) compiler->addFunctionCall(&switchBackdropToAndWait); } + compiler->addFunctionCall(&backdropNumber); compiler->addFunctionCall(&checkBackdropScripts); } @@ -750,7 +751,7 @@ void LooksBlocks::startBackdropScripts(VirtualMachine *vm, bool wait) { if (Stage *stage = vm->engine()->stage()) { if (stage->costumes().size() > 0) - vm->engine()->broadcastByPtr(stage->currentCostume()->broadcast(), vm, wait); + vm->engine()->startBackdropScripts(stage->currentCostume()->broadcast()); } } @@ -894,11 +895,14 @@ unsigned int LooksBlocks::randomBackdropAndWait(VirtualMachine *vm) unsigned int LooksBlocks::checkBackdropScripts(VirtualMachine *vm) { if (Stage *stage = vm->engine()->stage()) { - if ((stage->costumes().size() > 0) && vm->engine()->broadcastByPtrRunning(stage->currentCostume()->broadcast(), vm)) + long index = vm->getInput(0, 1)->toLong() - 1; + assert(stage->costumes().size() == 0 || index >= 0); + + if ((stage->costumes().size() > 0) && vm->engine()->broadcastByPtrRunning(stage->costumeAt(index)->broadcast())) vm->stop(true, true, true); } - return 0; + return 1; } unsigned int LooksBlocks::goToFront(VirtualMachine *vm) diff --git a/src/engine/internal/engine.cpp b/src/engine/internal/engine.cpp index b85d4876..58df9aac 100644 --- a/src/engine/internal/engine.cpp +++ b/src/engine/internal/engine.cpp @@ -23,10 +23,18 @@ #include "blocksectioncontainer.h" #include "timer.h" #include "clock.h" -#include "../../blocks/standardblocks.h" +#include "blocks/standardblocks.h" using namespace libscratchcpp; +const std::unordered_map Engine::m_hatRestartExistingThreads = { + { HatType::GreenFlag, true }, + { HatType::BroadcastReceived, true }, + { HatType::BackdropChanged, true }, + { HatType::CloneInit, false }, + { HatType::KeyPressed, false } +}; + Engine::Engine() : m_defaultTimer(std::make_unique()), m_timer(m_defaultTimer.get()), @@ -112,7 +120,7 @@ void Engine::compile() if (block->topLevel() && !block->shadow()) { auto section = blockSection(block->opcode()); if (section) { - auto script = std::make_shared