Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/engine/runtime.js
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,13 @@ class Runtime extends EventEmitter {
warpTimer: false
};

this.serializationOptions = {
/**
* Allows variables to be saved with types other than strings, numbers, and booleans.
*/
ignoreVariableSerialization: false
};

this.debug = false;

this._lastStepTime = Date.now();
Expand Down
28 changes: 21 additions & 7 deletions src/serialization/sb3.js
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,8 @@ const serializeSound = function (sound) {
// Using some bugs, it can be possible to get values like undefined, null, or complex objects into
// variables or lists. This will cause make the project unusable after exporting without JSON editing
// as it will fail validation in scratch-parser.
// To avoid this, we'll convert those objects to strings before saving them.
// To avoid this, we'll convert those objects to strings before saving them by default.
// If the project goes against this (for certain extensions), dont bother doing this step.
const isVariableValueSafeForJSON = value => (
typeof value === 'number' ||
typeof value === 'string' ||
Expand Down Expand Up @@ -516,11 +517,12 @@ const makeSafeForJSON = value => {
/**
* Serialize the given variables object.
* @param {object} variables The variables to be serialized.
* @param {boolean} optIgnoreVarTypes If true, will ignore variable type serialization
* @return {object} A serialized representation of the variables. They get
* separated by type to compress the representation of each given variable and
* reduce duplicate information.
*/
const serializeVariables = function (variables) {
const serializeVariables = function (variables, optIgnoreVarTypes) {
const obj = Object.create(null);
// separate out variables into types at the top level so we don't have
// keep track of a type for each
Expand All @@ -534,12 +536,18 @@ const serializeVariables = function (variables) {
continue;
}
if (v.type === Variable.LIST_TYPE) {
obj.lists[varId] = [v.name, makeSafeForJSON(v.value)];
obj.lists[varId] = [
v.name,
optIgnoreVarTypes ? v.value : makeSafeForJSON(v.value)
];
continue;
}

// otherwise should be a scalar type
obj.variables[varId] = [v.name, makeSafeForJSON(v.value)];
obj.variables[varId] = [
v.name,
optIgnoreVarTypes ? v.value : makeSafeForJSON(v.value)
];
// only scalar vars have the potential to be cloud vars
if (v.isCloud) obj.variables[varId].push(true);
}
Expand Down Expand Up @@ -580,14 +588,15 @@ const serializeComments = function (comments) {
* for saving and loading this target.
* @param {object} target The target to be serialized.
* @param {Set} extensions A set of extensions to add extension IDs to
* @param {boolean} optIgnoreVarTypes If true, will ignore variable type serialization
* @return {object} A serialized representation of the given target.
*/
const serializeTarget = function (target, extensions) {
const serializeTarget = function (target, extensions, optIgnoreVarTypes) {
const obj = Object.create(null);
let targetExtensions = [];
obj.isStage = target.isStage;
obj.name = obj.isStage ? 'Stage' : target.name;
const vars = serializeVariables(target.variables);
const vars = serializeVariables(target.variables, optIgnoreVarTypes);
obj.variables = vars.variables;
obj.lists = vars.lists;
obj.broadcasts = vars.broadcasts;
Expand Down Expand Up @@ -730,7 +739,12 @@ const serialize = function (runtime, targetId, {allowOptimization = true} = {})
});
}

const serializedTargets = flattenedOriginalTargets.map(t => serializeTarget(t, extensions))
const serializationOptions = runtime.serializationOptions;
const serializedTargets = flattenedOriginalTargets.map(t => serializeTarget(
t,
extensions,
serializationOptions.ignoreVariableSerialization
))
.map((serialized, index) => {
// can't serialize extensionStorage until the list of used extensions is fully known
const target = originalTargetsToSerialize[index];
Expand Down