Merge branch 'develop' of https://github.com/LLK/scratch-vm into boostextension

This commit is contained in:
Kevin Andersen 2019-02-14 13:31:13 -05:00
commit e99a217ba5
16 changed files with 2672 additions and 2611 deletions

5175
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -43,7 +43,7 @@
"jszip": "^3.1.5", "jszip": "^3.1.5",
"minilog": "3.1.0", "minilog": "3.1.0",
"nets": "3.2.0", "nets": "3.2.0",
"scratch-parser": "4.3.3", "scratch-parser": "4.3.4",
"scratch-sb1-converter": "0.2.6", "scratch-sb1-converter": "0.2.6",
"scratch-translate-extension-languages": "0.0.20181205140428", "scratch-translate-extension-languages": "0.0.20181205140428",
"socket.io-client": "2.0.4", "socket.io-client": "2.0.4",

View file

@ -12,6 +12,7 @@ const MonitorRecord = Record({
mode: 'default', mode: 'default',
sliderMin: 0, sliderMin: 0,
sliderMax: 100, sliderMax: 100,
isDiscrete: true,
x: null, // (x: null, y: null) Indicates that the monitor should be auto-positioned x: null, // (x: null, y: null) Indicates that the monitor should be auto-positioned
y: null, y: null,
width: 0, width: 0,

View file

@ -322,13 +322,17 @@ class ExtensionManager {
const menuItems = menuFunc.call(extensionObject, editingTargetID).map( const menuItems = menuFunc.call(extensionObject, editingTargetID).map(
item => { item => {
item = maybeFormatMessage(item, extensionMessageContext); item = maybeFormatMessage(item, extensionMessageContext);
if (typeof item === 'object') { switch (typeof item) {
case 'object':
return [ return [
maybeFormatMessage(item.text, extensionMessageContext), maybeFormatMessage(item.text, extensionMessageContext),
item.value item.value
]; ];
case 'string':
return [item, item];
default:
return item;
} }
return item;
}); });
if (!menuItems || menuItems.length < 1) { if (!menuItems || menuItems.length < 1) {

View file

@ -775,6 +775,12 @@ class Scratch3GdxForBlocks {
} }
getTilt (args) { getTilt (args) {
// Tilt values are calculated using acceleration due to gravity,
// so we need to return 0 when the peripheral is not connected.
if (!this._peripheral.isConnected()) {
return 0;
}
switch (args.TILT) { switch (args.TILT) {
case TiltAxisValues.FRONT: case TiltAxisValues.FRONT:
return Math.round(this._peripheral.getTiltFrontBack(false)); return Math.round(this._peripheral.getTiltFrontBack(false));

View file

@ -675,7 +675,7 @@ class Scratch3PenBlocks {
const hueValue = Cast.toNumber(args.HUE); const hueValue = Cast.toNumber(args.HUE);
const colorValue = hueValue / 2; const colorValue = hueValue / 2;
this._setOrChangeColorParam(ColorParam.COLOR, colorValue, penState, false); this._setOrChangeColorParam(ColorParam.COLOR, colorValue, penState, false);
this._setOrChangeColorParam(ColorParam.TRANSPARENCY, 0, penState, false);
this._legacyUpdatePenColor(penState); this._legacyUpdatePenColor(penState);
} }

View file

@ -26,7 +26,13 @@ const deserializeSound = function (sound, runtime, zip, assetFileName) {
return Promise.resolve(null); return Promise.resolve(null);
} }
const soundFile = zip.file(fileName); let soundFile = zip.file(fileName);
if (!soundFile) {
// look for assetfile in a flat list of files, or in a folder
const fileMatch = new RegExp(`^([^/]*/)?${fileName}$`);
soundFile = zip.file(fileMatch)[0]; // use first matching file
}
if (!soundFile) { if (!soundFile) {
log.error(`Could not find sound file associated with the ${sound.name} sound.`); log.error(`Could not find sound file associated with the ${sound.name} sound.`);
return Promise.resolve(null); return Promise.resolve(null);
@ -100,7 +106,13 @@ const deserializeCostume = function (costume, runtime, zip, assetFileName, textL
return Promise.resolve(null); return Promise.resolve(null);
} }
const costumeFile = zip.file(fileName); let costumeFile = zip.file(fileName);
if (!costumeFile) {
// look for assetfile in a flat list of files, or in a folder
const fileMatch = new RegExp(`^([^/]*/)?${fileName}$`);
costumeFile = zip.file(fileMatch)[0]; // use the first matched file
}
if (!costumeFile) { if (!costumeFile) {
log.error(`Could not find costume file associated with the ${costume.name} costume.`); log.error(`Could not find costume file associated with the ${costume.name} costume.`);
return Promise.resolve(null); return Promise.resolve(null);

View file

@ -381,6 +381,7 @@ const parseMonitorObject = (object, runtime, targets, extensions) => {
mode: object.mode, mode: object.mode,
sliderMin: object.sliderMin, sliderMin: object.sliderMin,
sliderMax: object.sliderMax, sliderMax: object.sliderMax,
isDiscrete: object.isDiscrete,
x: object.x, x: object.x,
y: object.y, y: object.y,
width: object.width, width: object.width,

View file

@ -506,6 +506,7 @@ const serializeMonitors = function (monitors) {
if (monitorData.mode !== 'list') { if (monitorData.mode !== 'list') {
serializedMonitor.sliderMin = monitorData.sliderMin; serializedMonitor.sliderMin = monitorData.sliderMin;
serializedMonitor.sliderMax = monitorData.sliderMax; serializedMonitor.sliderMax = monitorData.sliderMax;
serializedMonitor.isDiscrete = monitorData.isDiscrete;
} }
return serializedMonitor; return serializedMonitor;
}); });

BIN
test/fixtures/default_nested.sb2 vendored Normal file

Binary file not shown.

Binary file not shown.

View file

@ -7,6 +7,10 @@ module.exports = {
}, },
extractProjectJson: function (path) { extractProjectJson: function (path) {
const zip = new AdmZip(path); const zip = new AdmZip(path);
return JSON.parse(zip.readAsText('project.json', 'utf8')); const projectEntry = zip.getEntries().filter(item => item.entryName.match(/project\.json/))[0];
if (projectEntry) {
return JSON.parse(zip.readAsText(projectEntry.entryName, 'utf8'));
}
return null;
} }
}; };

View file

@ -0,0 +1,52 @@
const path = require('path');
const test = require('tap').test;
const makeTestStorage = require('../fixtures/make-test-storage');
const extractProjectJson = require('../fixtures/readProjectFile').extractProjectJson;
const renderedTarget = require('../../src/sprites/rendered-target');
const runtime = require('../../src/engine/runtime');
const sb2 = require('../../src/serialization/sb2');
test('spec', t => {
t.type(sb2.deserialize, 'function');
t.end();
});
test('nested default/*', t => {
// Get SB2 JSON (string)
const uri = path.resolve(__dirname, '../fixtures/default_nested.sb2');
const json = extractProjectJson(uri, 'default');
// Create runtime instance & load SB2 into it
const rt = new runtime();
rt.attachStorage(makeTestStorage());
sb2.deserialize(json, rt).then(({targets}) => {
// Test
t.type(json, 'object');
t.type(rt, 'object');
t.type(targets, 'object');
t.ok(targets[0] instanceof renderedTarget);
t.type(targets[0].id, 'string');
t.type(targets[0].blocks, 'object');
t.type(targets[0].variables, 'object');
t.type(targets[0].comments, 'object');
t.equal(targets[0].isOriginal, true);
t.equal(targets[0].currentCostume, 0);
t.equal(targets[0].isOriginal, true);
t.equal(targets[0].isStage, true);
t.ok(targets[1] instanceof renderedTarget);
t.type(targets[1].id, 'string');
t.type(targets[1].blocks, 'object');
t.type(targets[1].variables, 'object');
t.type(targets[1].comments, 'object');
t.equal(targets[1].isOriginal, true);
t.equal(targets[1].currentCostume, 0);
t.equal(targets[1].isOriginal, true);
t.equal(targets[1].isStage, false);
t.end();
});
});

View file

@ -37,6 +37,7 @@ test('importing sb2 project with monitors', t => {
t.equal(monitorRecord.mode, 'slider'); t.equal(monitorRecord.mode, 'slider');
t.equal(monitorRecord.sliderMin, -200); // Make sure these are imported for sliders. t.equal(monitorRecord.sliderMin, -200); // Make sure these are imported for sliders.
t.equal(monitorRecord.sliderMax, 30); t.equal(monitorRecord.sliderMax, 30);
t.equal(monitorRecord.isDiscrete, false);
t.equal(monitorRecord.x, 5); // These are imported for all monitors, just check once. t.equal(monitorRecord.x, 5); // These are imported for all monitors, just check once.
t.equal(monitorRecord.y, 59); t.equal(monitorRecord.y, 59);
t.equal(monitorRecord.visible, true); t.equal(monitorRecord.visible, true);
@ -61,8 +62,8 @@ test('importing sb2 project with monitors', t => {
t.equal(monitorRecord.opcode, 'data_listcontents'); t.equal(monitorRecord.opcode, 'data_listcontents');
t.equal(monitorRecord.mode, 'list'); t.equal(monitorRecord.mode, 'list');
t.equal(monitorRecord.visible, true); t.equal(monitorRecord.visible, true);
t.equal(monitorRecord.width, 104); // Make sure these are imported from lists. t.equal(monitorRecord.width, 106); // Make sure these are imported from lists.
t.equal(monitorRecord.height, 204); t.equal(monitorRecord.height, 206);
// Backdrop name monitor is visible, not sprite specific // Backdrop name monitor is visible, not sprite specific
// should get imported with id that references the name parameter // should get imported with id that references the name parameter

View file

@ -54,6 +54,7 @@ test('saving and loading sb2 project with monitors preserves sliderMin and slide
t.equal(monitorRecord.mode, 'slider'); t.equal(monitorRecord.mode, 'slider');
t.equal(monitorRecord.sliderMin, -200); // Make sure these are imported for sliders. t.equal(monitorRecord.sliderMin, -200); // Make sure these are imported for sliders.
t.equal(monitorRecord.sliderMax, 30); t.equal(monitorRecord.sliderMax, 30);
t.equal(monitorRecord.isDiscrete, false);
t.equal(monitorRecord.x, 5); // These are imported for all monitors, just check once. t.equal(monitorRecord.x, 5); // These are imported for all monitors, just check once.
t.equal(monitorRecord.y, 59); t.equal(monitorRecord.y, 59);
t.equal(monitorRecord.visible, true); t.equal(monitorRecord.visible, true);
@ -78,8 +79,8 @@ test('saving and loading sb2 project with monitors preserves sliderMin and slide
t.equal(monitorRecord.opcode, 'data_listcontents'); t.equal(monitorRecord.opcode, 'data_listcontents');
t.equal(monitorRecord.mode, 'list'); t.equal(monitorRecord.mode, 'list');
t.equal(monitorRecord.visible, true); t.equal(monitorRecord.visible, true);
t.equal(monitorRecord.width, 104); // Make sure these are imported from lists. t.equal(monitorRecord.width, 106); // Make sure these are imported from lists.
t.equal(monitorRecord.height, 204); t.equal(monitorRecord.height, 206);
// Backdrop name monitor is visible, not sprite specific // Backdrop name monitor is visible, not sprite specific
// should get imported with id that references the name parameter // should get imported with id that references the name parameter

View file

@ -39,10 +39,9 @@ test('importing sb3 project with monitors', t => {
t.equal(monitorRecord.opcode, 'data_variable'); t.equal(monitorRecord.opcode, 'data_variable');
t.equal(monitorRecord.mode, 'default'); t.equal(monitorRecord.mode, 'default');
// The following few properties are imported for all monitors, just check once. // The following few properties are imported for all monitors, just check once.
// sliderMin and sliderMax are currently not implemented,
// but should still get default values serialized and deserialized correctly
t.equal(monitorRecord.sliderMin, 0); t.equal(monitorRecord.sliderMin, 0);
t.equal(monitorRecord.sliderMax, 100); t.equal(monitorRecord.sliderMax, 100);
t.equal(monitorRecord.isDiscrete, true); // The default if not present
t.equal(monitorRecord.x, 10); t.equal(monitorRecord.x, 10);
t.equal(monitorRecord.y, 62); t.equal(monitorRecord.y, 62);
// Height and width are only used for list monitors and should default to 0 // Height and width are only used for list monitors and should default to 0