Skip to content

Commit 47d4a80

Browse files
committed
Implement broadcast and wait block
1 parent a2fbc65 commit 47d4a80

File tree

6 files changed

+67
-8
lines changed

6 files changed

+67
-8
lines changed

src/blocks/eventblocks.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ EventBlocks::EventBlocks()
1111
// Blocks
1212
addHatBlock("event_whenflagclicked");
1313
addCompileFunction("event_broadcast", &compileBroadcast);
14+
addCompileFunction("event_broadcastandwait", &compileBroadcastAndWait);
1415
addCompileFunction("event_whenbroadcastreceived", &compileWhenBroadcastReceived);
1516

1617
// Inputs
@@ -36,6 +37,22 @@ void EventBlocks::compileBroadcast(Compiler *compiler)
3637
compiler->addFunctionCall(&broadcast);
3738
}
3839

40+
void EventBlocks::compileBroadcastAndWait(Compiler *compiler)
41+
{
42+
auto input = compiler->input(BROADCAST_INPUT);
43+
compiler->addInput(input);
44+
if (input->type() != Input::Type::ObscuredShadow) {
45+
input->primaryValue()->setValue(compiler->engine()->findBroadcast(input->primaryValue()->value().toString()));
46+
compiler->addFunctionCall(&broadcastByIndex);
47+
compiler->addInput(input);
48+
compiler->addFunctionCall(&checkBroadcastByIndex);
49+
} else {
50+
compiler->addFunctionCall(&broadcast);
51+
compiler->addInput(input);
52+
compiler->addFunctionCall(&checkBroadcast);
53+
}
54+
}
55+
3956
void EventBlocks::compileWhenBroadcastReceived(Compiler *compiler)
4057
{
4158
auto broadcast = std::static_pointer_cast<Broadcast>(compiler->field(BROADCAST_OPTION)->valuePtr());
@@ -53,3 +70,17 @@ unsigned int EventBlocks::broadcastByIndex(VirtualMachine *vm)
5370
vm->engine()->broadcast(vm->getInput(0, 1)->toLong(), vm);
5471
return 1;
5572
}
73+
74+
unsigned int EventBlocks::checkBroadcast(VirtualMachine *vm)
75+
{
76+
if (vm->engine()->broadcastRunning(vm->engine()->findBroadcast(vm->getInput(0, 1)->toString())))
77+
vm->stop(true, true, true);
78+
return 1;
79+
}
80+
81+
unsigned int EventBlocks::checkBroadcastByIndex(VirtualMachine *vm)
82+
{
83+
if (vm->engine()->broadcastRunning(vm->getInput(0, 1)->toLong()))
84+
vm->stop(true, true, true);
85+
return 1;
86+
}

src/blocks/eventblocks.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,14 @@ class LIBSCRATCHCPP_EXPORT EventBlocks : public IBlockSection
2626
std::string name() const override;
2727

2828
static void compileBroadcast(Compiler *compiler);
29+
static void compileBroadcastAndWait(Compiler *compiler);
2930
static void compileWhenBroadcastReceived(Compiler *compiler);
3031

3132
private:
3233
static unsigned int broadcast(VirtualMachine *vm);
3334
static unsigned int broadcastByIndex(VirtualMachine *vm);
35+
static unsigned int checkBroadcast(VirtualMachine *vm);
36+
static unsigned int checkBroadcastByIndex(VirtualMachine *vm);
3437
};
3538

3639
} // namespace libscratchcpp

src/engine/engine.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,11 +121,19 @@ void Engine::frame()
121121
m_breakFrame = false;
122122

123123
do {
124+
std::string opcode;
125+
for (auto const &[key, value] : m_scripts) {
126+
if (value.get() == script)
127+
opcode = key->opcode();
128+
}
124129
auto ret = script->run(m_scriptPositions[i]);
125130
if (script->savePos())
126131
m_scriptPositions[i] = ret;
127-
if (script->atEnd())
132+
if (script->atEnd()) {
133+
for (auto &[key, value] : m_broadcastMap)
134+
value.erase(std::remove(value.begin(), value.end(), script), value.end());
128135
m_scriptsToRemove.push_back(script);
136+
}
129137
} while (!script->atEnd() && !m_breakFrame);
130138
}
131139

@@ -185,7 +193,7 @@ void Engine::startScript(std::shared_ptr<Block> topLevelBlock, std::shared_ptr<T
185193
/*! Starts the script of the broadcast with the given index. */
186194
void libscratchcpp::Engine::broadcast(unsigned int index, VirtualMachine *sourceScript)
187195
{
188-
const std::vector<VirtualMachine *> scripts = m_broadcastMap[index];
196+
const std::vector<VirtualMachine *> &scripts = m_broadcastMap[index];
189197
for (auto vm : scripts) {
190198
auto it = std::find(m_runningScripts.begin(), m_runningScripts.end(), vm);
191199
if (it != m_runningScripts.end()) {
@@ -256,6 +264,12 @@ void Engine::run()
256264
}
257265
}
258266

267+
/*! Returns true if there are any running script of the broadcast with the given index. */
268+
bool Engine::broadcastRunning(unsigned int index)
269+
{
270+
return !m_broadcastMap[index].empty();
271+
}
272+
259273
/*!
260274
* Call this from a block implementation to force a "screen refresh".
261275
* \note This has no effect in "run without screen refresh" custom blocks.

src/engine/engine.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ class LIBSCRATCHCPP_EXPORT Engine
4040
void stopTarget(Target *target, VirtualMachine *exceptScript);
4141
void run();
4242

43+
bool broadcastRunning(unsigned int index);
44+
4345
void breakFrame();
4446
void stayOnCurrentBlock();
4547
void breakAtomicScript();

src/engine/virtualmachine.cpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -612,22 +612,27 @@ do_list_get_item : {
612612
FREE_REGS(1);
613613
DISPATCH();
614614

615-
do_exec:
616-
FREE_REGS(m_functions[*++pos](this));
615+
do_exec : {
616+
auto ret = m_functions[*++pos](this);
617617
if (m_stop) {
618618
m_stop = false;
619-
if (m_regCount > 0) {
620-
std::cout << "warning: VM: " << m_regCount << " registers were leaked by the script; this is most likely a bug in the VM or in the compiler" << std::endl;
621-
}
622619
m_callTree.clear();
623620
m_procedureArgTree.clear();
624621
m_procedureArgs = nullptr;
625622
m_nextProcedureArgs = nullptr;
626623
if (!m_atomic)
627624
m_engine->breakFrame();
625+
if (m_goBack) {
626+
m_goBack = false;
627+
pos -= instruction_arg_count[OP_EXEC] + 1;
628+
m_freeExecRegs = ret;
629+
} else
630+
FREE_REGS(ret);
628631
return pos;
629632
}
633+
FREE_REGS(ret);
630634
DISPATCH();
635+
}
631636

632637
do_init_procedure:
633638
m_procedureArgTree.push_back({});

src/engine/virtualmachine.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,12 +115,14 @@ class LIBSCRATCHCPP_EXPORT VirtualMachine
115115
* Use this to stop the script from a function.
116116
* \param[in] savePos Changes the return value of savePos().
117117
* \param[in] breakAtomic Whether to break the frame after stopping the script.
118+
* \param[in] goBack Whether to go back so that the current instruction can run again in the future.
118119
*/
119-
void stop(bool savePos = true, bool breakAtomic = false)
120+
void stop(bool savePos = true, bool breakAtomic = false, bool goBack = false)
120121
{
121122
m_stop = true;
122123
m_savePos = savePos;
123124
m_atomic = !breakAtomic;
125+
m_goBack = goBack;
124126
}
125127

126128
/*! Returns true if the VM has reached the vm::OP_HALT instruction. */
@@ -155,6 +157,8 @@ class LIBSCRATCHCPP_EXPORT VirtualMachine
155157
bool m_atomic;
156158
bool m_stop = false;
157159
bool m_savePos = true;
160+
bool m_goBack = false;
161+
unsigned int m_freeExecRegs;
158162

159163
unsigned int **m_procedures = nullptr;
160164
std::vector<unsigned int *> m_proceduresVector;

0 commit comments

Comments
 (0)