Skip to content

Commit 294c238

Browse files
committed
Use variables and lists from clones in Script
1 parent 8792b25 commit 294c238

File tree

5 files changed

+117
-20
lines changed

5 files changed

+117
-20
lines changed

include/scratchcpp/script.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class Target;
1515
class IEngine;
1616
class Value;
1717
class VirtualMachine;
18+
class Variable;
1819
class List;
1920
class ScriptPrivate;
2021

@@ -34,7 +35,7 @@ class LIBSCRATCHCPP_EXPORT Script
3435
void setProcedures(const std::vector<unsigned int *> &procedures);
3536
void setFunctions(const std::vector<BlockFunc> &functions);
3637
void setConstValues(const std::vector<Value> &values);
37-
void setVariables(const std::vector<Value *> &variables);
38+
void setVariables(const std::vector<Variable *> &variables);
3839
void setLists(const std::vector<List *> &lists);
3940

4041
std::shared_ptr<VirtualMachine> start();

src/engine/internal/engine.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ void Engine::compile()
112112
if (m_scripts.count(block) == 1) {
113113
m_scripts[block]->setProcedures(procedureBytecodes);
114114
m_scripts[block]->setConstValues(compiler.constValues());
115-
m_scripts[block]->setVariables(compiler.variablePtrs());
115+
m_scripts[block]->setVariables(compiler.variables());
116116
m_scripts[block]->setLists(compiler.lists());
117117
}
118118
}

src/engine/script.cpp

Lines changed: 65 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
#include <scratchcpp/script.h>
44
#include <scratchcpp/virtualmachine.h>
5+
#include <scratchcpp/variable.h>
6+
#include <scratchcpp/list.h>
7+
#include <scratchcpp/sprite.h>
8+
#include <scratchcpp/iengine.h>
9+
#include <iostream>
510

611
#include "script_p.h"
712

@@ -44,16 +49,66 @@ std::shared_ptr<VirtualMachine> Script::start()
4449
return start(impl->target);
4550
}
4651

47-
/*! Starts the script (creates a virtual machine). */
52+
/*! Starts the script (creates a virtual machine) as the given target (might be a clone). */
4853
std::shared_ptr<VirtualMachine> Script::start(Target *target)
4954
{
5055
auto vm = std::make_shared<VirtualMachine>(target, impl->engine, this);
5156
vm->setBytecode(impl->bytecode);
5257
vm->setProcedures(impl->procedures);
5358
vm->setFunctions(impl->functions);
5459
vm->setConstValues(impl->constValues);
55-
vm->setVariables(impl->variables);
56-
vm->setLists(impl->lists);
60+
61+
Sprite *sprite = nullptr;
62+
if (target && !target->isStage())
63+
sprite = dynamic_cast<Sprite *>(target);
64+
65+
if (impl->target && sprite && sprite->isClone() && impl->engine) {
66+
Target *root = sprite->cloneRoot();
67+
68+
if (root != impl->target) {
69+
std::cout << "warning: a clone tried to start a script of another target (this is a bug in libscratchcpp or in your code!)" << std::endl;
70+
vm->setVariables(impl->variableValues.data());
71+
vm->setLists(impl->lists.data());
72+
return vm;
73+
}
74+
75+
// Use internal variables and lists from the clone
76+
std::vector<Value *> variables;
77+
std::vector<List *> lists;
78+
79+
for (const auto &var : impl->variables) {
80+
Target *owner = impl->engine->variableOwner(var);
81+
82+
if (owner && (owner == root)) {
83+
auto cloneVar = sprite->variableAt(sprite->findVariableById(var->id()));
84+
assert(cloneVar);
85+
86+
if (cloneVar)
87+
variables.push_back(cloneVar->valuePtr());
88+
} else
89+
variables.push_back(var->valuePtr());
90+
}
91+
92+
for (const auto &list : impl->lists) {
93+
Target *owner = impl->engine->listOwner(list);
94+
95+
if (owner && (owner == root)) {
96+
auto cloneList = sprite->listAt(sprite->findListById(list->id()));
97+
assert(cloneList);
98+
99+
if (cloneList)
100+
lists.push_back(cloneList.get());
101+
} else
102+
lists.push_back(list);
103+
}
104+
105+
vm->setVariablesVector(variables);
106+
vm->setListsVector(lists);
107+
} else {
108+
vm->setVariables(impl->variableValues.data());
109+
vm->setLists(impl->lists.data());
110+
}
111+
57112
return vm;
58113
}
59114

@@ -79,15 +134,17 @@ void Script::setConstValues(const std::vector<Value> &values)
79134
}
80135

81136
/*! Sets the list of variables. */
82-
void Script::setVariables(const std::vector<Value *> &variables)
137+
void Script::setVariables(const std::vector<Variable *> &variables)
83138
{
84-
impl->variablesVector = variables;
85-
impl->variables = impl->variablesVector.data();
139+
impl->variables = variables;
140+
impl->variableValues.clear();
141+
142+
for (const auto &var : variables)
143+
impl->variableValues.push_back(var->valuePtr());
86144
}
87145

88146
/*! Sets the list of lists. */
89147
void Script::setLists(const std::vector<List *> &lists)
90148
{
91-
impl->listsVector = lists;
92-
impl->lists = impl->listsVector.data();
149+
impl->lists = lists;
93150
}

src/engine/script_p.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ namespace libscratchcpp
1212

1313
class Target;
1414
class IEngine;
15+
class Variable;
1516
class List;
1617

1718
struct ScriptPrivate
@@ -34,11 +35,10 @@ struct ScriptPrivate
3435
const Value *constValues = nullptr;
3536
std::vector<Value> constValuesVector;
3637

37-
Value **variables = nullptr;
38-
std::vector<Value *> variablesVector;
38+
std::vector<Value *> variableValues;
39+
std::vector<Variable *> variables;
3940

40-
List **lists = nullptr;
41-
std::vector<List *> listsVector;
41+
std::vector<List *> lists;
4242
};
4343

4444
} // namespace libscratchcpp

test/script/script_test.cpp

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
#include <scratchcpp/script.h>
22
#include <scratchcpp/virtualmachine.h>
33
#include <scratchcpp/target.h>
4+
#include <scratchcpp/sprite.h>
5+
#include <scratchcpp/variable.h>
46
#include <scratchcpp/list.h>
57
#include <enginemock.h>
68

79
#include "../common.h"
810

911
using namespace libscratchcpp;
1012

13+
using ::testing::Return;
14+
1115
class ScriptTest : public testing::Test
1216
{
1317
public:
@@ -45,11 +49,13 @@ TEST_F(ScriptTest, Start)
4549
static std::vector<BlockFunc> functions = { &testFunction };
4650
static std::vector<Value> constValues = { "test" };
4751

48-
std::unique_ptr<Value> var = std::make_unique<Value>();
49-
static std::vector<Value *> variables = { var.get() };
52+
std::unique_ptr<Variable> var1 = std::make_unique<Variable>("a", "", Value());
53+
std::unique_ptr<Variable> var2 = std::make_unique<Variable>("b", "", Value());
54+
static std::vector<Variable *> variables = { var1.get(), var2.get() };
5055

51-
std::unique_ptr<List> list = std::make_unique<List>("", "");
52-
static std::vector<List *> lists = { list.get() };
56+
std::unique_ptr<List> list1 = std::make_unique<List>("c", "");
57+
std::unique_ptr<List> list2 = std::make_unique<List>("d", "");
58+
static std::vector<List *> lists = { list1.get(), list2.get() };
5359

5460
Script script1(nullptr, nullptr);
5561

@@ -85,7 +91,7 @@ TEST_F(ScriptTest, Start)
8591
ASSERT_EQ(vm->procedures()[0], procedures[0]);
8692
ASSERT_EQ(vm->functions()[0], functions[0]);
8793
ASSERT_EQ(vm->constValues()[0].toString(), constValues[0].toString());
88-
ASSERT_EQ(vm->variables()[0], variables[0]);
94+
ASSERT_EQ(vm->variables()[0], variables[0]->valuePtr());
8995
ASSERT_EQ(vm->lists()[0], lists[0]);
9096

9197
Target target;
@@ -96,6 +102,39 @@ TEST_F(ScriptTest, Start)
96102
ASSERT_EQ(vm->procedures()[0], procedures[0]);
97103
ASSERT_EQ(vm->functions()[0], functions[0]);
98104
ASSERT_EQ(vm->constValues()[0].toString(), constValues[0].toString());
99-
ASSERT_EQ(vm->variables()[0], variables[0]);
105+
ASSERT_EQ(vm->variables()[0], variables[0]->valuePtr());
106+
ASSERT_EQ(vm->lists()[0], lists[0]);
107+
108+
Sprite root;
109+
root.setEngine(&m_engine);
110+
root.addVariable(std::make_shared<Variable>("b", "", Value()));
111+
root.addList(std::make_shared<List>("d", ""));
112+
113+
EXPECT_CALL(m_engine, initClone).Times(1);
114+
auto clone = root.clone();
115+
116+
Script script4(&root, &m_engine);
117+
script4.setBytecode(bytecode);
118+
script4.setProcedures(procedures);
119+
script4.setFunctions(functions);
120+
script4.setConstValues(constValues);
121+
script4.setVariables(variables);
122+
script4.setLists(lists);
123+
124+
EXPECT_CALL(m_engine, variableOwner(var1.get())).WillOnce(Return(&target));
125+
EXPECT_CALL(m_engine, variableOwner(var2.get())).WillOnce(Return(&root));
126+
EXPECT_CALL(m_engine, listOwner(list1.get())).WillOnce(Return(&target));
127+
EXPECT_CALL(m_engine, listOwner(list2.get())).WillOnce(Return(&root));
128+
vm = script4.start(clone.get());
129+
130+
ASSERT_TRUE(vm);
131+
ASSERT_EQ(vm->target(), clone.get());
132+
ASSERT_EQ(vm->bytecode()[0], bytecode[0]);
133+
ASSERT_EQ(vm->procedures()[0], procedures[0]);
134+
ASSERT_EQ(vm->functions()[0], functions[0]);
135+
ASSERT_EQ(vm->constValues()[0].toString(), constValues[0].toString());
136+
ASSERT_EQ(vm->variables()[0], variables[0]->valuePtr());
137+
ASSERT_EQ(vm->variables()[1], clone->variableAt(clone->findVariableById("b"))->valuePtr());
100138
ASSERT_EQ(vm->lists()[0], lists[0]);
139+
ASSERT_EQ(vm->lists()[1], clone->listAt(clone->findListById("d")).get());
101140
}

0 commit comments

Comments
 (0)