libscratchcpp
A library for C++ based Scratch project players
Loading...
Searching...
No Matches
Extensions

An extension is a group of Scratch blocks, for example motion blocks.

Creating an extension

To create a custom extension, subclass IExtension and override name() and description() functions to return the name and the description of the extension. Then override registerBlocks() where you'll register the compile functions for blocks.

It's recommended to use the libscratchcpp namespace like this in your extension class:

using namespace libscratchcpp;
The main namespace of the library.
Definition asset.h:10

Adding blocks

See the Scratch Wiki for more information about blocks.

Scratch projects are compiled by the Compiler class. To add a block, you have to let the compiler know how to compile it. Start by defining a compile function. For example, the compile function for a hello world block would look like this:

class MyExtension : public IExtension {
public:
...
static void compileHelloWorld(Compiler *compiler);
static unsigned int helloWorld(VirtualMachine *vm);
};
void MyExtension::compileHelloWorld(Compiler *compiler) {
compiler->addFunctionCall(&helloWorld);
}
unsigned int MyExtension::helloWorld(VirtualMachine *vm) {
std::cout << "Hello, world!" << std::endl;
return 0;
}
The Compiler class provides API for compiling Scratch scripts.
Definition compiler.h:33
CompilerValue * addFunctionCall(const std::string &functionName, StaticType returnType=StaticType::Void, const ArgTypes &argTypes={}, const Args &args={})
Definition compiler.cpp:141
The IExtension class is an interface for extensions.
Definition iextension.h:18
Note
Make sure the functions are static.

Register the compile function using the addCompileFunction() method in link libscratchcpp::IExtension::registerBlocks() registerBlocks() :

MyExtension::registerBlocks(IEngine *engine) {
engine->addCompileFunction(this, "myextension_helloworld", &MyExtension::compileHelloWorld);
}
The IEngine interface provides an API for running Scratch projects.
Definition iengine.h:41
virtual void addCompileFunction(IExtension *extension, const std::string &opcode, BlockComp f)=0

Where myextension_helloworld is the opcode of the hello world block.

Adding inputs

To add inputs, create an Inputs enumeration in your extension:

class MyExtension : public IExtension {
enum Inputs {
TEXT
};
...
};

Then add inputs in link libscratchcpp::IExtension::registerBlocks() registerBlocks() :

MyExtension::registerBlocks(IEngine *engine) {
...
engine->addInput(this, "TEXT", TEXT);
}

The compiler will assign the input name with the TEXT ID. In this case, the ID is 0 because it's the first member of the enumeration.

To add the input to the compiled code, call the addInput() function:

void MyExtension::compileHelloWorld(Compiler *compiler) {
compiler->addInput(TEXT);
compiler->addFunctionCall(&helloWorld);
}
CompilerValue * addInput(const std::string &name)
Definition compiler.cpp:240

The value of the input can be read during runtime using the getInput() function:

unsigned int MyExtension::helloWorld(VirtualMachine *vm) {
std::cout << "Hello, " << vm->getInput(0, 1)->toString() << "!" << std::endl;
return 1;
}
Note
The order of the inputs is the same as in the compile function. Do not use the Inputs enumeration in runtime functions.
vm->getInput(0, 1)

The first argument is the index of the input and the second argument is the amount of inputs.

Note
Make sure to return the amount of inputs in the helloWorld function.

Adding fields

Fields are drop-down menus into which one cannot drop a reporter. Fields have a predefined set of values.

class MyExtension : public IExtension {
...
enum Fields {
ANIMAL
};
enum FieldValues {
Cat,
Dog
};
...
};
MyExtension::registerBlocks(IEngine *engine) {
...
engine->addField(this, "ANIMAL", ANIMAL);
engine->addFieldValue(this, "Cat", Cat);
engine->addFieldValue(this, "Dog", Dog);
}

Because fields are handled at compile time, you can read them from the compile function:

void MyExtension::compileHelloWorld(Compiler *compiler) {
int id = compiler->field(ANIMAL)->specialValueId();
switch(id) {
case Cat:
compiler->addFunctionCall(&helloCat);
break;
case Dog:
compiler->addFunctionCall(&helloDog);
break;
default:
break;
}
}
unsigned int MyExtension::helloCat(VirtualMachine *vm) {
std::cout << "Hello, cat!" << std::endl;
return 0;
}
unsigned int MyExtension::helloDog(VirtualMachine *vm) {
std::cout << "Hello, dog!" << std::endl;
return 0;
}
Field * field(const std::string &name) const
Definition compiler.cpp:731
Note
Don't confuse specialValueId() with valueId() because valueId() stores the ID of the block, variable, list or broadcast selected in the dropdown list.

To get a pointer to the block, variable, list or broadcast selected in the dropdown list, use valuePtr() .

Registering the extension

Register the extension before loading a project, using the ScratchConfiguration class:

static void registerExtension(std::shared_ptr< IExtension > extension)
Definition scratchconfiguration.cpp:12