diff --git a/src/dispatch/shared-dispatch.js b/src/dispatch/shared-dispatch.js index 85d38bde2..1e4785bce 100644 --- a/src/dispatch/shared-dispatch.js +++ b/src/dispatch/shared-dispatch.js @@ -91,6 +91,16 @@ class SharedDispatch { } } + /** + * Check if a particular service lives on another worker. + * @param {string} service - the service to check. + * @returns {boolean} - true if the service is remote (calls must cross a Worker boundary), false otherwise. + * @private + */ + _isRemoteService (service) { + return this._getServiceProvider(service).isRemote; + } + /** * Like {@link call}, but force the call to be posted through a particular communication channel. * @param {object} provider - send the call through this object's `postMessage` function. diff --git a/src/extension-support/extension-manager.js b/src/extension-support/extension-manager.js index d5a3e07ea..bdbc274f1 100644 --- a/src/extension-support/extension-manager.js +++ b/src/extension-support/extension-manager.js @@ -198,7 +198,17 @@ class ExtensionManager { blockInfo.opcode = this._sanitizeID(blockInfo.opcode); blockInfo.func = blockInfo.func ? this._sanitizeID(blockInfo.func) : blockInfo.opcode; blockInfo.text = blockInfo.text || blockInfo.opcode; - blockInfo.func = dispatch.call.bind(dispatch, serviceName, blockInfo.func); + + /** + * This is only here because the VM performs poorly when blocks return promises. + * @TODO make it possible for the VM to resolve a promise and continue during the same frame. + */ + if (dispatch._isRemoteService(serviceName)) { + blockInfo.func = dispatch.call.bind(dispatch, serviceName, blockInfo.func); + } else { + const serviceObject = dispatch.services[serviceName]; + blockInfo.func = serviceObject[blockInfo.func].bind(serviceObject); + } return blockInfo; } } diff --git a/src/serialization/sb2_specmap.js b/src/serialization/sb2_specmap.js index 8f574624b..2024b239e 100644 --- a/src/serialization/sb2_specmap.js +++ b/src/serialization/sb2_specmap.js @@ -500,27 +500,27 @@ const specMap = { ] }, 'clearPenTrails': { - opcode: 'pen_clear', + opcode: 'pen.clear', argMap: [ ] }, 'stampCostume': { - opcode: 'pen_stamp', + opcode: 'pen.stamp', argMap: [ ] }, 'putPenDown': { - opcode: 'pen_pendown', + opcode: 'pen.penDown', argMap: [ ] }, 'putPenUp': { - opcode: 'pen_penup', + opcode: 'pen.penUp', argMap: [ ] }, 'penColor:': { - opcode: 'pen_setpencolortocolor', + opcode: 'pen.setPenColorToColor', argMap: [ { type: 'input', @@ -530,7 +530,7 @@ const specMap = { ] }, 'changePenHueBy:': { - opcode: 'pen_changepencolorby', + opcode: 'pen.changePenHueBy', argMap: [ { type: 'input', @@ -540,7 +540,7 @@ const specMap = { ] }, 'setPenHueTo:': { - opcode: 'pen_setpencolortonum', + opcode: 'pen.setPenHueToNumber', argMap: [ { type: 'input', @@ -550,7 +550,7 @@ const specMap = { ] }, 'changePenShadeBy:': { - opcode: 'pen_changepenshadeby', + opcode: 'pen.changePenShadeBy', argMap: [ { type: 'input', @@ -560,7 +560,7 @@ const specMap = { ] }, 'setPenShadeTo:': { - opcode: 'pen_setpenshadeto', + opcode: 'pen.setPenShadeToNumber', argMap: [ { type: 'input', @@ -570,7 +570,7 @@ const specMap = { ] }, 'changePenSizeBy:': { - opcode: 'pen_changepensizeby', + opcode: 'pen.changePenSizeBy', argMap: [ { type: 'input', @@ -580,7 +580,7 @@ const specMap = { ] }, 'penSize:': { - opcode: 'pen_setpensizeto', + opcode: 'pen.setPenSizeTo', argMap: [ { type: 'input', diff --git a/test/integration/pen.js b/test/integration/pen.js index 25c2121d8..025735bac 100644 --- a/test/integration/pen.js +++ b/test/integration/pen.js @@ -1,8 +1,10 @@ +const Worker = require('tiny-worker'); const path = require('path'); const test = require('tap').test; const Scratch3PenBlocks = require('../../src/blocks/scratch3_pen'); const VirtualMachine = require('../../src/index'); +const dispatch = require('../../src/dispatch/central-dispatch'); const makeTestStorage = require('../fixtures/make-test-storage'); const extract = require('../fixtures/extract'); @@ -10,6 +12,9 @@ const extract = require('../fixtures/extract'); const uri = path.resolve(__dirname, '../fixtures/pen.sb2'); const project = extract(uri); +// By default Central Dispatch works with the Worker class built into the browser. Tell it to use TinyWorker instead. +dispatch.workerClass = Worker; + test('pen', t => { const vm = new VirtualMachine(); vm.attachStorage(makeTestStorage()); @@ -42,14 +47,16 @@ test('pen', t => { vm.clear(); vm.setCompatibilityMode(false); vm.setTurboMode(false); - vm.loadProject(project).then(() => { - vm.greenFlag(); + vm.loadProject(project) + .then(() => vm.extensionManager.loadExtensionURL('pen')) /** @TODO: loadProject should load extensions */ + .then(() => { + vm.greenFlag(); - // After two seconds, get playground data and stop - setTimeout(() => { - vm.getPlaygroundData(); - vm.stopAll(); - }, 2000); - }); + // After two seconds, get playground data and stop + setTimeout(() => { + vm.getPlaygroundData(); + vm.stopAll(); + }, 2000); + }); }); });