Skip to content
This repository has been archived by the owner on Dec 6, 2017. It is now read-only.

Saving and Loading Data

perriern edited this page Oct 22, 2014 · 9 revisions

Serialization (how to save/load data)

###Classes

  • All

All objects that need to have user-customizable data will have to save/load things at some point. Wanaplan provides a powerful system to save/load javascript objects. This process is called Serialization/Deserialization.

#####Basic (de)serialization sample

Here is the (de)serialization code for BABYLON.Vector2 objects :

BABYLON.Vector2.prototype.serialize = function () {
	var sObject = {
		class: { 
                    name: "BABYLON.Vector2"
                },
		x: this.x,
		y: this.y
	};

	return sObject;
}

BABYLON.Vector2.Deserialize = function (hybrid) {

	var object = new BABYLON.Vector2(hybrid.x, hybrid.y);

	return object;
}

If you want a class to be "serialization-ready", you have to implement these 2 functions : a method serialize within the prototype of your class, and a static method Deserialize outside the prototype.

Serialization

As you can see, the data has to be encapsuled in a generic JS object (that will end up in a JSON file). This object must contain the attribute class that itself contains the attribute name. This is for the purpose of reinstancing the right class when deserializing the object. You can put whatever you want in this generic object, since you have full control of what happens to the data when you save/load it. This object should then be returned.

Deserialization

The static method is called based on what was in the field { class : { name }}. In the example above, when the Wanaplan parser will find BABYLON.Vector2, it will know it has to call the BABYLON.Vector2's Deserialize method. This method of course has an argument hybrid, which is the serialized object returned by serialize in the first place.

Recursivity

Most of the time, you will need to serialize complex objects, with multiple classes encapsulated.

Wanaplan provides functions for serialization and deserialization, that will recursively serialize encapsuled objects : API.serializeObjects and API.deserializeObjects.

Usage

You must use these functions as following :

API.serializeObject(object, optionalTarget, whiteList, blackList);
API.deserializeObject(object, optionalTarget, whiteList, blackList);	

where :

  • object is your object being (de)serialized.
  • optionalTarget is an optional object to which you will add (de)serialized data. This is particularly useful when using inheritance.
  • whiteList is an optional list of properties you want to (de)serialize in the specified object. This is useful when you want to (de)serialize only a few members.
  • blackList is an optional list of properties you don't want to (de)serialize in the specified object. This is useful when you want to (de)serialize not all, but most of the members.

Note : By default, when not providing white or black lists, all your object's members will be (de)serialized except its methods and its null or undefined members.

Use case

Here is a sample serialization code provided for 2 custom classes, using inheritance.

// Parent Class
var Parent = function () {
	var a = "foo";
	var vector = new BABYLON.Vector2();
};

// Child Class
var Child = function () {
	Parent.call(this);

	var b = "bar";
	var color = new BABYLON.Color3();
};

Child.prototype = Object.create(Parent.prototype);

// Parent Serialization
Parent.prototype.serialize = function() {
	var sObject = { class : { name : "Parent" } };
		
	// We only serialize the 'vector' field and put the result in 'sObject'
	API.serializeObject(this, sObject, ['vector']);
		
	return sObject;
};

// Child Serialization
Child.prototype.serialize = function() {
	// Use parent serialization
	var sObject = Parent.prototype.serialize.call(this);

	// Serialize all the properties
	API.serializeObject(this, sObject);

	return sObject;
};

// Parent Deserialization
Parent.Deserialize = function (hybrid) {
	var object = new Parent();
	
	// We separate effective deserialization for the sake of inheritance
	object.deserialize(hybrid);

	return object;
};

Parent.prototype.deserialize = function (hybrid) {
	// We only deserialize the field 'vector'
	// This should be optional, since the only field serialized was 'vector'
	// So there is nothing else to deserialize

	API.deserializeObject(hybrid, this, ['vector']);
};

// Child Deserialization
Child.Deserialize = function (hybrid) {
	var object = new Child();

	// Use parent deserialization
	Parent.prototype.deserialize.call(this, hybrid);
	
	// Effective child deserialization
	// We blacklist the field 'vector', since it has 
	// already been deserialized in the parent

	API.deserializeObject(hybrid, this, null, ['vector']);
	return object;
};

There are many ways to use serialization, the one displayed above is just for the sake of the demonstration and genericity. In this case, the serialization could be much shorter.

Adding data to storage

We have seen how you can make your data classes "serialization-ready". Now the last step is to add them to a storage space, where Wanaplan can effectively retrieve them on saving/loading passes.

This is very easily done with 2 API functions :

  • API.getData(field);
  • API.setData(field, content)

The serialization storage is in fact a simple javascript map, and you can set its fields by using setData. You can then retrieve data by using getData.

Let's see a short example using our previous use case :

var c0 = new Child();
var p0 = new Parent();

// Store these 2 objects in a 'people' field
API.setData('people', [ c0, p0 ]);

var c1 = new Child();

// Add c1 to the storage
var people = API.getData('people');
people.push(c1);

Now, say that you save and quit the plan. When you open it back later, you can restore your data, by simply doing :

var people  = API.getData('people');
console.log(people); 
// Prints an Array containing c0, p0 and c1