diff --git a/src/serialization/serialize-assets.js b/src/serialization/serialize-assets.js new file mode 100644 index 000000000..0177d2189 --- /dev/null +++ b/src/serialization/serialize-assets.js @@ -0,0 +1,55 @@ +/** + * Serialize all the assets of the given type ('sounds' or 'costumes') + * in the provided runtime into an array of file descriptors. + * A file descriptor is an object containing the name of the file + * to be written and the contents of the file, the serialized asset. + * @param {Runtime} runtime The runtime with the assets to be serialized + * @param {string} assetType The type of assets to be serialized: 'sounds' | 'costumes' + * @returns {Array} An array of file descriptors for each asset + */ +const serializeAssets = function (runtime, assetType) { + const targets = runtime.targets; + const assetDescs = []; + for (let i = 0; i < targets.length; i++) { + const currTarget = targets[i]; + const currAssets = currTarget.sprite[assetType]; + for (let j = 0; j < currAssets.length; j++) { + const currAsset = currAssets[j]; + const assetId = currAsset.assetId; + const storage = runtime.storage; + const asset = storage.get(assetId); + assetDescs.push({ + fileName: assetType === 'sound' ? + currAsset.md5 : `${assetId}.${currAsset.dataFormat}`, + fileContent: asset.data}); + } + } + return assetDescs; +}; + +/** + * Serialize all the sounds in the provided runtime into an array of file + * descriptors. A file descriptor is an object containing the name of the file + * to be written and the contents of the file, the serialized sound. + * @param {Runtime} runtime The runtime with the sounds to be serialized + * @returns {Array} An array of file descriptors for each sound + */ +const serializeSounds = function (runtime) { + return serializeAssets(runtime, 'sounds'); +}; + +/** + * Serialize all the costumes in the provided runtime into an array of file + * descriptors. A file descriptor is an object containing the name of the file + * to be written and the contents of the file, the serialized costume. + * @param {Runtime} runtime The runtime with the costumes to be serialized + * @returns {Array} An array of file descriptors for each costume + */ +const serializeCostumes = function (runtime) { + return serializeAssets(runtime, 'costumes'); +}; + +module.exports = { + serializeSounds, + serializeCostumes +}; diff --git a/src/virtual-machine.js b/src/virtual-machine.js index d40a2a28b..be4b5c551 100644 --- a/src/virtual-machine.js +++ b/src/virtual-machine.js @@ -15,6 +15,7 @@ const Variable = require('./engine/variable'); const {loadCostume} = require('./import/load-costume.js'); const {loadSound} = require('./import/load-sound.js'); +const {serializeSounds, serializeCostumes} = require('./serialization/serialize-assets'); const RESERVED_NAMES = ['_mouse_', '_stage_', '_edge_', '_myself_', '_random_']; @@ -206,7 +207,14 @@ class VirtualMachine extends EventEmitter { */ saveProjectSb3 () { // @todo: Handle other formats, e.g., Scratch 1.4, Scratch 2.0. - return this.toJSON(); + const soundDescs = serializeSounds(this.runtime); + const costumeDescs = serializeCostumes(this.runtime); + + return { + projectJson: this.toJSON(), + sounds: soundDescs, + costumes: costumeDescs + }; } /**