SB2 Import for Broadcast Blocks (not including the input field functionality for 'broadcast' and 'broadcast and wait

'). Currently we also cannot import projects where messages and variables share names.
This commit is contained in:
Karishma Chadha 2017-12-01 10:29:32 -05:00
parent e5378d323d
commit 80da989f01
5 changed files with 62 additions and 24 deletions
src/serialization

View file

@ -88,17 +88,18 @@ const flatten = function (blocks) {
* a list of blocks in a branch (e.g., in forever),
* or a list of blocks in an argument (e.g., move [pick random...]).
* @param {Array.<object>} blockList SB2 JSON-format block list.
* @param {Function} addBroadcastMsg function to update broadcast message name map
* @param {Function} getVariableId function to retreive a variable's ID based on name
* @param {ImportedExtensionsInfo} extensions - (in/out) parsed extension information will be stored here.
* @return {Array.<object>} Scratch VM-format block list.
*/
const parseBlockList = function (blockList, getVariableId, extensions) {
const parseBlockList = function (blockList, addBroadcastMsg, getVariableId, extensions) {
const resultingList = [];
let previousBlock = null; // For setting next.
for (let i = 0; i < blockList.length; i++) {
const block = blockList[i];
// eslint-disable-next-line no-use-before-define
const parsedBlock = parseBlock(block, getVariableId, extensions);
const parsedBlock = parseBlock(block, addBroadcastMsg, getVariableId, extensions);
if (typeof parsedBlock === 'undefined') continue;
if (previousBlock) {
parsedBlock.parent = previousBlock.id;
@ -115,16 +116,17 @@ const parseBlockList = function (blockList, getVariableId, extensions) {
* This should only handle top-level scripts that include X, Y coordinates.
* @param {!object} scripts Scripts object from SB2 JSON.
* @param {!Blocks} blocks Blocks object to load parsed blocks into.
* @param {Function} addBroadcastMsg function to update broadcast message name map
* @param {Function} getVariableId function to retreive a variable's ID based on name
* @param {ImportedExtensionsInfo} extensions - (in/out) parsed extension information will be stored here.
*/
const parseScripts = function (scripts, blocks, getVariableId, extensions) {
const parseScripts = function (scripts, blocks, addBroadcastMsg, getVariableId, extensions) {
for (let i = 0; i < scripts.length; i++) {
const script = scripts[i];
const scriptX = script[0];
const scriptY = script[1];
const blockList = script[2];
const parsedBlockList = parseBlockList(blockList, getVariableId, extensions);
const parsedBlockList = parseBlockList(blockList, addBroadcastMsg, getVariableId, extensions);
if (parsedBlockList[0]) {
// Adjust script coordinates to account for
// larger block size in scratch-blocks.
@ -166,6 +168,23 @@ const generateVariableIdGetter = (function () {
};
}());
const generateBroadcastMsgId = function (name) {
return `broadcastMsgId-${name}`;
};
const globalBroadcastMsgStateGenerator = (function () {
let broadcastMsgNameMap = {};
return function (topLevel) {
if (topLevel) broadcastMsgNameMap = {};
return {
broadcastMsgMapUpdater: function (name) {
broadcastMsgNameMap[name] = generateBroadcastMsgId(name);
},
globalBroadcastMsgs: broadcastMsgNameMap
};
};
}());
/**
* Parse a single "Scratch object" and create all its in-memory VM objects.
* TODO: parse the "info" section, especially "savedExtensions"
@ -227,6 +246,9 @@ const parseScratchObject = function (object, runtime, extensions, topLevel) {
const getVariableId = generateVariableIdGetter(target.id, topLevel);
const globalBroadcastMsgObj = globalBroadcastMsgStateGenerator(topLevel);
const addBroadcastMsg = globalBroadcastMsgObj.broadcastMsgMapUpdater;
// Load target properties from JSON.
if (object.hasOwnProperty('variables')) {
for (let j = 0; j < object.variables.length; j++) {
@ -244,7 +266,7 @@ const parseScratchObject = function (object, runtime, extensions, topLevel) {
// If included, parse any and all scripts/blocks on the object.
if (object.hasOwnProperty('scripts')) {
parseScripts(object.scripts, blocks, getVariableId, extensions);
parseScripts(object.scripts, blocks, addBroadcastMsg, getVariableId, extensions);
}
if (object.hasOwnProperty('lists')) {
@ -317,6 +339,21 @@ const parseScratchObject = function (object, runtime, extensions, topLevel) {
Promise.all(
childrenPromises
).then(children => {
// Need create broadcast msgs as variables after
// all other targets have finished processing.
if (target.isStage) {
const allBroadcastMsgs = globalBroadcastMsgObj.globalBroadcastMsgs;
for (const msgName in allBroadcastMsgs) {
const msgId = allBroadcastMsgs[msgName];
const newMsg = new Variable(
msgId,
msgName,
Variable.BROADCAST_MESSAGE_TYPE,
false
);
target.variables[newMsg.id] = newMsg;
}
}
let targets = [target];
for (let n = 0; n < children.length; n++) {
targets = targets.concat(children[n]);
@ -349,11 +386,12 @@ const sb2import = function (json, runtime, optForceSprite) {
/**
* Parse a single SB2 JSON-formatted block and its children.
* @param {!object} sb2block SB2 JSON-formatted block.
* @param {Function} addBroadcastMsg function to update broadcast message name map
* @param {Function} getVariableId function to retrieve a variable's ID based on name
* @param {ImportedExtensionsInfo} extensions - (in/out) parsed extension information will be stored here.
* @return {object} Scratch VM format block, or null if unsupported object.
*/
const parseBlock = function (sb2block, getVariableId, extensions) {
const parseBlock = function (sb2block, addBroadcastMsg, getVariableId, extensions) {
// First item in block object is the old opcode (e.g., 'forward:').
const oldOpcode = sb2block[0];
// Convert the block using the specMap. See sb2specmap.js.
@ -404,10 +442,10 @@ const parseBlock = function (sb2block, getVariableId, extensions) {
let innerBlocks;
if (typeof providedArg[0] === 'object' && providedArg[0]) {
// Block list occupies the input.
innerBlocks = parseBlockList(providedArg, getVariableId, extensions);
innerBlocks = parseBlockList(providedArg, addBroadcastMsg, getVariableId, extensions);
} else {
// Single block occupies the input.
innerBlocks = [parseBlock(providedArg, getVariableId, extensions)];
innerBlocks = [parseBlock(providedArg, addBroadcastMsg, getVariableId, extensions)];
}
let previousBlock = null;
for (let j = 0; j < innerBlocks.length; j++) {
@ -493,6 +531,11 @@ const parseBlock = function (sb2block, getVariableId, extensions) {
if (expectedArg.fieldName === 'VARIABLE' || expectedArg.fieldName === 'LIST') {
// Add `id` property to variable fields
activeBlock.fields[expectedArg.fieldName].id = getVariableId(providedArg);
} else if (expectedArg.fieldName === 'BROADCAST_OPTION') {
// add the name in this field to the broadcast msg name map
addBroadcastMsg(providedArg);
const broadcastId = generateBroadcastMsgId(providedArg);
activeBlock.fields[expectedArg.fieldName].id = broadcastId;
}
const varType = expectedArg.variableType;
if (typeof varType === 'string') {

View file

@ -656,7 +656,8 @@ const specMap = {
argMap: [
{
type: 'field',
fieldName: 'BROADCAST_OPTION'
fieldName: 'BROADCAST_OPTION',
variableType: Variable.BROADCAST_MESSAGE_TYPE
}
]
},
@ -664,9 +665,9 @@ const specMap = {
opcode: 'event_broadcast',
argMap: [
{
type: 'input',
inputOp: 'event_broadcast_menu',
inputName: 'BROADCAST_OPTION'
type: 'field',
fieldName: 'BROADCAST_OPTION',
variableType: Variable.BROADCAST_MESSAGE_TYPE
}
]
},
@ -674,9 +675,9 @@ const specMap = {
opcode: 'event_broadcastandwait',
argMap: [
{
type: 'input',
inputOp: 'event_broadcast_menu',
inputName: 'BROADCAST_OPTION'
type: 'field',
fieldName: 'BROADCAST_OPTION',
variableType: Variable.BROADCAST_MESSAGE_TYPE
}
]
},