|
| 1 | +const JSZip = require('jszip'); |
| 2 | +const log = require('../util/log'); |
| 3 | + |
| 4 | +/** |
| 5 | + * Deserializes sound from file into storage cache so that it can |
| 6 | + * be loaded into the runtime. |
| 7 | + * @param {object} sound Descriptor for sound from sb3 file |
| 8 | + * @param {Runtime} runtime The runtime containing the storage to cache the sounds in |
| 9 | + * @param {JSZip} zip The zip containing the sound file being described by `sound` |
| 10 | + * @return {Promise} Promise that resolves after the described sound has been stored |
| 11 | + * into the runtime storage cache, the sound was already stored, or an error has |
| 12 | + * occurred. |
| 13 | + */ |
| 14 | +const deserializeSound = function (sound, runtime, zip) { |
| 15 | + const fileName = sound.md5; // The md5 property has the full file name |
| 16 | + const storage = runtime.storage; |
| 17 | + if (!storage) { |
| 18 | + log.error('No storage module present; cannot load sound asset: ', fileName); |
| 19 | + return Promise.resolve(null); |
| 20 | + } |
| 21 | + |
| 22 | + const assetId = sound.assetId; |
| 23 | + |
| 24 | + // TODO Is there a faster way to check that this asset |
| 25 | + // has already been initialized? |
| 26 | + if (storage.get(assetId)) { |
| 27 | + // This sound has already been cached. |
| 28 | + return Promise.resolve(null); |
| 29 | + } |
| 30 | + |
| 31 | + const soundFile = zip.file(fileName); |
| 32 | + if (!soundFile) { |
| 33 | + log.error(`Could not find sound file associated with the ${sound.name} sound.`); |
| 34 | + return Promise.resolve(null); |
| 35 | + } |
| 36 | + let dataFormat = null; |
| 37 | + if (sound.dataFormat.toLowerCase() === 'wav') { |
| 38 | + dataFormat = storage.DataFormat.WAV; |
| 39 | + } |
| 40 | + if (!JSZip.support.uint8array) { |
| 41 | + log.error('JSZip uint8array is not supported in this browser.'); |
| 42 | + return Promise.resolve(null); |
| 43 | + } |
| 44 | + |
| 45 | + return soundFile.async('uint8array').then(data => { |
| 46 | + storage.builtinHelper.cache( |
| 47 | + storage.AssetType.Sound, |
| 48 | + dataFormat, |
| 49 | + data, |
| 50 | + assetId |
| 51 | + ); |
| 52 | + }); |
| 53 | +}; |
| 54 | + |
| 55 | +/** |
| 56 | + * Deserializes costume from file into storage cache so that it can |
| 57 | + * be loaded into the runtime. |
| 58 | + * @param {object} costume Descriptor for costume from sb3 file |
| 59 | + * @param {Runtime} runtime The runtime containing the storage to cache the costumes in |
| 60 | + * @param {JSZip} zip The zip containing the costume file being described by `costume` |
| 61 | + * @return {Promise} Promise that resolves after the described costume has been stored |
| 62 | + * into the runtime storage cache, the costume was already stored, or an error has |
| 63 | + * occurred. |
| 64 | + */ |
| 65 | +const deserializeCostume = function (costume, runtime, zip) { |
| 66 | + const storage = runtime.storage; |
| 67 | + const assetId = costume.assetId; |
| 68 | + const fileName = costume.md5 ? |
| 69 | + costume.md5 : |
| 70 | + `${assetId}.${costume.dataFormat}`; // The md5 property has the full file name |
| 71 | + |
| 72 | + if (!storage) { |
| 73 | + log.error('No storage module present; cannot load costume asset: ', fileName); |
| 74 | + return Promise.resolve(null); |
| 75 | + } |
| 76 | + |
| 77 | + |
| 78 | + // TODO Is there a faster way to check that this asset |
| 79 | + // has already been initialized? |
| 80 | + if (storage.get(assetId)) { |
| 81 | + // This costume has already been cached. |
| 82 | + return Promise.resolve(null); |
| 83 | + } |
| 84 | + |
| 85 | + const costumeFile = zip.file(fileName); |
| 86 | + if (!costumeFile) { |
| 87 | + log.error(`Could not find costume file associated with the ${costume.name} costume.`); |
| 88 | + return Promise.resolve(null); |
| 89 | + } |
| 90 | + let dataFormat = null; |
| 91 | + let assetType = null; |
| 92 | + const costumeFormat = costume.dataFormat.toLowerCase(); |
| 93 | + if (costumeFormat === 'svg') { |
| 94 | + dataFormat = storage.DataFormat.SVG; |
| 95 | + assetType = storage.AssetType.ImageVector; |
| 96 | + } else if (costumeFormat === 'png') { |
| 97 | + dataFormat = storage.DataFormat.PNG; |
| 98 | + assetType = storage.AssetType.ImageBitmap; |
| 99 | + } else { |
| 100 | + log.error(`Unexpected file format for costume: ${costumeFormat}`); |
| 101 | + } |
| 102 | + if (!JSZip.support.uint8array) { |
| 103 | + log.error('JSZip uint8array is not supported in this browser.'); |
| 104 | + return Promise.resolve(null); |
| 105 | + } |
| 106 | + |
| 107 | + return costumeFile.async('uint8array').then(data => { |
| 108 | + storage.builtinHelper.cache( |
| 109 | + assetType, |
| 110 | + dataFormat, |
| 111 | + data, |
| 112 | + assetId |
| 113 | + ); |
| 114 | + }); |
| 115 | +}; |
| 116 | + |
| 117 | +module.exports = { |
| 118 | + deserializeSound, |
| 119 | + deserializeCostume |
| 120 | +}; |
0 commit comments