mirror of
https://github.com/scratchfoundation/scratch-vm.git
synced 2025-01-11 10:39:56 -05:00
WIP for demo
This commit is contained in:
parent
aaa7784d39
commit
d43749d675
6 changed files with 78 additions and 13 deletions
|
@ -115,6 +115,12 @@ class SharedDispatch {
|
||||||
_remoteTransferCall (provider, service, method, transfer, ...args) {
|
_remoteTransferCall (provider, service, method, transfer, ...args) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const responseId = this._storeCallbacks(resolve, reject);
|
const responseId = this._storeCallbacks(resolve, reject);
|
||||||
|
|
||||||
|
/** @TODO: remove this hack! this is just here so we don't try to send `util` to a worker */
|
||||||
|
if ((args.length > 0) && (typeof args[args.length - 1].yield === 'function')) {
|
||||||
|
args.pop();
|
||||||
|
}
|
||||||
|
|
||||||
if (transfer) {
|
if (transfer) {
|
||||||
provider.postMessage({service, method, responseId, args}, transfer);
|
provider.postMessage({service, method, responseId, args}, transfer);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -294,6 +294,14 @@ class Runtime extends EventEmitter {
|
||||||
return 'MONITORS_UPDATE';
|
return 'MONITORS_UPDATE';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event name for reporting that an extension was added.
|
||||||
|
* @const {string}
|
||||||
|
*/
|
||||||
|
static get EXTENSION_WAS_ADDED () {
|
||||||
|
return 'EXTENSION_WAS_ADDED';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* How rapidly we try to step threads by default, in ms.
|
* How rapidly we try to step threads by default, in ms.
|
||||||
*/
|
*/
|
||||||
|
@ -371,10 +379,12 @@ class Runtime extends EventEmitter {
|
||||||
|
|
||||||
for (const blockInfo of extensionInfo.blocks) {
|
for (const blockInfo of extensionInfo.blocks) {
|
||||||
const convertedBlock = this._convertForScratchBlocks(blockInfo, categoryInfo);
|
const convertedBlock = this._convertForScratchBlocks(blockInfo, categoryInfo);
|
||||||
const opcode = convertedBlock.json.id;
|
const opcode = convertedBlock.json.type;
|
||||||
categoryInfo.blocks.push(convertedBlock);
|
categoryInfo.blocks.push(convertedBlock);
|
||||||
this._primitives[opcode] = convertedBlock.info.func;
|
this._primitives[opcode] = convertedBlock.info.func;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.emit(Runtime.EXTENSION_WAS_ADDED, categoryInfo.blocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -387,10 +397,8 @@ class Runtime extends EventEmitter {
|
||||||
_convertForScratchBlocks (blockInfo, categoryInfo) {
|
_convertForScratchBlocks (blockInfo, categoryInfo) {
|
||||||
const extendedOpcode = `${categoryInfo.id}.${blockInfo.opcode}`;
|
const extendedOpcode = `${categoryInfo.id}.${blockInfo.opcode}`;
|
||||||
const blockJSON = {
|
const blockJSON = {
|
||||||
id: extendedOpcode,
|
type: extendedOpcode,
|
||||||
inputsInline: true,
|
inputsInline: true,
|
||||||
previousStatement: null, // null = available connection; undefined = hat block
|
|
||||||
nextStatement: null, // null = available connection; undefined = terminal
|
|
||||||
category: categoryInfo.name,
|
category: categoryInfo.name,
|
||||||
colour: categoryInfo.color1,
|
colour: categoryInfo.color1,
|
||||||
colourSecondary: categoryInfo.color2,
|
colourSecondary: categoryInfo.color2,
|
||||||
|
@ -436,6 +444,10 @@ class Runtime extends EventEmitter {
|
||||||
switch (blockInfo.blockType) {
|
switch (blockInfo.blockType) {
|
||||||
case BlockType.COMMAND:
|
case BlockType.COMMAND:
|
||||||
blockJSON.outputShape = ScratchBlocks.OUTPUT_SHAPE_SQUARE;
|
blockJSON.outputShape = ScratchBlocks.OUTPUT_SHAPE_SQUARE;
|
||||||
|
blockJSON.previousStatement = null; // null = available connection; undefined = hat
|
||||||
|
if (!blockInfo.isTerminal) {
|
||||||
|
blockJSON.nextStatement = null; // null = available connection; undefined = terminal
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case BlockType.REPORTER:
|
case BlockType.REPORTER:
|
||||||
blockJSON.output = 'String'; // TODO: distinguish number & string here?
|
blockJSON.output = 'String'; // TODO: distinguish number & string here?
|
||||||
|
@ -447,7 +459,7 @@ class Runtime extends EventEmitter {
|
||||||
break;
|
break;
|
||||||
case BlockType.HAT:
|
case BlockType.HAT:
|
||||||
blockJSON.outputShape = ScratchBlocks.OUTPUT_SHAPE_SQUARE;
|
blockJSON.outputShape = ScratchBlocks.OUTPUT_SHAPE_SQUARE;
|
||||||
delete blockJSON.previousStatement;
|
blockJSON.nextStatement = null; // null = available connection; undefined = terminal
|
||||||
break;
|
break;
|
||||||
case BlockType.CONDITIONAL:
|
case BlockType.CONDITIONAL:
|
||||||
// Statement inputs get names like 'SUBSTACK', 'SUBSTACK2', 'SUBSTACK3', ...
|
// Statement inputs get names like 'SUBSTACK', 'SUBSTACK2', 'SUBSTACK3', ...
|
||||||
|
@ -458,6 +470,8 @@ class Runtime extends EventEmitter {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
blockJSON.outputShape = ScratchBlocks.OUTPUT_SHAPE_SQUARE;
|
blockJSON.outputShape = ScratchBlocks.OUTPUT_SHAPE_SQUARE;
|
||||||
|
blockJSON.previousStatement = null; // null = available connection; undefined = hat
|
||||||
|
blockJSON.nextStatement = null; // null = available connection; undefined = terminal
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -659,7 +673,7 @@ class Runtime extends EventEmitter {
|
||||||
if (this.threads[i].topBlock === topBlockId && this.threads[i].status !== Thread.STATUS_DONE) {
|
if (this.threads[i].topBlock === topBlockId && this.threads[i].status !== Thread.STATUS_DONE) {
|
||||||
const blockContainer = opts.target.blocks;
|
const blockContainer = opts.target.blocks;
|
||||||
const opcode = blockContainer.getOpcode(blockContainer.getBlock(topBlockId));
|
const opcode = blockContainer.getOpcode(blockContainer.getBlock(topBlockId));
|
||||||
|
|
||||||
if (this.getIsEdgeActivatedHat(opcode) && this.threads[i].stackClick !== opts.stackClick) {
|
if (this.getIsEdgeActivatedHat(opcode) && this.threads[i].stackClick !== opts.stackClick) {
|
||||||
// Allow edge activated hat thread stack click to coexist with
|
// Allow edge activated hat thread stack click to coexist with
|
||||||
// edge activated hat thread that runs every frame
|
// edge activated hat thread that runs every frame
|
||||||
|
|
|
@ -65,10 +65,6 @@ class ExtensionManager {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
foo () {
|
|
||||||
return this.loadExtensionURL('extensions/example-extension.js');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load an extension by URL
|
* Load an extension by URL
|
||||||
* @param {string} extensionURL - the URL for the extension to load
|
* @param {string} extensionURL - the URL for the extension to load
|
||||||
|
@ -77,7 +73,7 @@ class ExtensionManager {
|
||||||
loadExtensionURL (extensionURL) {
|
loadExtensionURL (extensionURL) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
// If we `require` this at the global level it breaks non-webpack targets, including tests
|
// If we `require` this at the global level it breaks non-webpack targets, including tests
|
||||||
const ExtensionWorker = require('worker-loader!./extension-worker');
|
const ExtensionWorker = require('worker-loader?name=extension-worker.js!./extension-worker');
|
||||||
|
|
||||||
this.pendingExtensions.push({extensionURL, resolve, reject});
|
this.pendingExtensions.push({extensionURL, resolve, reject});
|
||||||
dispatch.addWorker(new ExtensionWorker());
|
dispatch.addWorker(new ExtensionWorker());
|
||||||
|
|
|
@ -33,6 +33,28 @@ class ExampleExtension {
|
||||||
// Required: the list of blocks implemented by this extension,
|
// Required: the list of blocks implemented by this extension,
|
||||||
// in the order intended for display.
|
// in the order intended for display.
|
||||||
blocks: [
|
blocks: [
|
||||||
|
{
|
||||||
|
opcode: 'example-noop',
|
||||||
|
blockType: Scratch.BlockType.COMMAND,
|
||||||
|
blockAllThreads: false,
|
||||||
|
text: 'do nothing',
|
||||||
|
func: 'noop'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
opcode: 'example-conditional',
|
||||||
|
blockType: Scratch.BlockType.CONDITIONAL,
|
||||||
|
branchCount: 4,
|
||||||
|
isTerminal: true,
|
||||||
|
blockAllThreads: false,
|
||||||
|
text: 'choose [BRANCH]',
|
||||||
|
arguments: {
|
||||||
|
BRANCH: {
|
||||||
|
type: Scratch.ArgumentType.NUMBER,
|
||||||
|
defaultValue: 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
func: 'noop'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
// Required: the machine-readable name of this operation.
|
// Required: the machine-readable name of this operation.
|
||||||
// This will appear in project JSON. Must not contain a '.' character.
|
// This will appear in project JSON. Must not contain a '.' character.
|
||||||
|
@ -110,6 +132,18 @@ class ExampleExtension {
|
||||||
// ['sprite', 'stage']
|
// ['sprite', 'stage']
|
||||||
filter: ['someBlocks.wedo2', 'sprite', 'stage']
|
filter: ['someBlocks.wedo2', 'sprite', 'stage']
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
opcode: 'example-Boolean',
|
||||||
|
blockType: Scratch.BlockType.BOOLEAN,
|
||||||
|
text: 'return true',
|
||||||
|
func: 'returnTrue'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
opcode: 'example-hat',
|
||||||
|
blockType: Scratch.BlockType.HAT,
|
||||||
|
text: 'after forever',
|
||||||
|
func: 'returnFalse'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
// Another block...
|
// Another block...
|
||||||
}
|
}
|
||||||
|
@ -179,6 +213,17 @@ class ExampleExtension {
|
||||||
|
|
||||||
return ['Letter ', args.LETTER_NUM, ' of ', args.TEXT, ' is ', result, '.'].join('');
|
return ['Letter ', args.LETTER_NUM, ' of ', args.TEXT, ' is ', result, '.'].join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
noop () {
|
||||||
|
}
|
||||||
|
|
||||||
|
returnTrue () {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
returnFalse () {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Scratch.extensions.register(new ExampleExtension());
|
Scratch.extensions.register(new ExampleExtension());
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
const VirtualMachine = require('./virtual-machine');
|
const VirtualMachine = require('./virtual-machine');
|
||||||
|
|
||||||
const CentralDispatch = require('./dispatch/central-dispatch');
|
const CentralDispatch = require('./dispatch/central-dispatch');
|
||||||
const ExtensionManager = require('./extension-support/extension-manager');
|
|
||||||
|
|
||||||
global.Scratch = global.Scratch || {};
|
global.Scratch = global.Scratch || {};
|
||||||
global.Scratch.dispatch = CentralDispatch;
|
global.Scratch.dispatch = CentralDispatch;
|
||||||
global.Scratch.extensions = new ExtensionManager();
|
|
||||||
|
|
||||||
module.exports = VirtualMachine;
|
module.exports = VirtualMachine;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
const EventEmitter = require('events');
|
const EventEmitter = require('events');
|
||||||
|
|
||||||
const centralDispatch = require('./dispatch/central-dispatch');
|
const centralDispatch = require('./dispatch/central-dispatch');
|
||||||
|
const ExtensionManager = require('./extension-support/extension-manager');
|
||||||
const log = require('./util/log');
|
const log = require('./util/log');
|
||||||
const Runtime = require('./engine/runtime');
|
const Runtime = require('./engine/runtime');
|
||||||
const sb2 = require('./serialization/sb2');
|
const sb2 = require('./serialization/sb2');
|
||||||
|
@ -63,6 +64,11 @@ class VirtualMachine extends EventEmitter {
|
||||||
this.runtime.on(Runtime.MONITORS_UPDATE, monitorList => {
|
this.runtime.on(Runtime.MONITORS_UPDATE, monitorList => {
|
||||||
this.emit(Runtime.MONITORS_UPDATE, monitorList);
|
this.emit(Runtime.MONITORS_UPDATE, monitorList);
|
||||||
});
|
});
|
||||||
|
this.runtime.on(Runtime.EXTENSION_WAS_ADDED, blocksInfo => {
|
||||||
|
this.emit(Runtime.EXTENSION_WAS_ADDED, blocksInfo);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.extensionManager = new ExtensionManager();
|
||||||
|
|
||||||
this.blockListener = this.blockListener.bind(this);
|
this.blockListener = this.blockListener.bind(this);
|
||||||
this.flyoutBlockListener = this.flyoutBlockListener.bind(this);
|
this.flyoutBlockListener = this.flyoutBlockListener.bind(this);
|
||||||
|
|
Loading…
Reference in a new issue