Skip to main content

News

Topic: [code] Object Serialization (Read 2783 times) previous topic - next topic

  • Radnen
  • [*][*][*][*][*]
  • Senior Staff
  • Wise Warrior
[code] Object Serialization
This piece of code is from my radlib library, but I'm putting it here because others might benefit from having this in their game, whether or not they want the full RadLib library.

These two functions, Serialize and Deserialize will store/recall JS objects, restoring their prototypes and non-serializable sphere objects. In Serialize, a new property is tacked on to an object: "zztype", it stores the constructor of the object that created it. Deserialize will call that constructor and then proceed to fill in the stored fields. The reason for this is twofold, one, when the object is re-created it becomes an object of the type of it's constructor rather than 'object' (JSON stringify/parse will turn all objects into general JS objects and strip the methods off of them), two, any sphere objects such as images will be reattached since usually they are created in the constructor function and since they are only used for display: we don't tend to store images/fonts/windowstyles, so they don't have to be saved.

Both Serialize and Deserialize do a deep inspection/clone, so nested objects are also affected.

Code: (javascript) [Select]

/**
* Serialize(obj : object);
*  - Use this to JSON an object; AND preserve the data type.
**/
function Serialize(obj)
{
function Make(obj) {
var o = { zztype: obj.constructor.name };
for (var i in obj) {
if (!(obj[i] instanceof Array) && typeof obj[i] == "object")
o[i] = Make(obj[i]);
else
o[i] = obj[i];
}
return o;
}

return JSON.stringify(Make(obj));
}

/**
* Deserialize(s : string);
*  - Use this to parse a JSON object; AND restore the methods.
**/
function Deserialize(s)
{
function Make(o) {
var obj = new this[o.zztype]();
for (var i in o) {
if (!(o[i] instanceof Array) && o[i] typeof "object")
obj[i] = Make(o[i]);
else
obj[i] = o[i];
}
delete obj.zztype;
return obj;
}

return Make(JSON.parse(s));
}


Therefore, you can now make a class like so:

Code: (javascript) [Select]

function Item() {
  this.image = LoadImage("dagger.png"); // an image... which can't be saved to file...
  this.damage = 5; // this however can; even with JSON.
}

// but this method will be stripped during JSON creation
Item.prototype.swing = function() {
  Print("Did " + this.damage + " damage!");
}

var item = new Item();
item.damage += 2; // I upgraded it!!

// serialization keeps an object, well the same object!
var s = Serialize(item);
File.save("item", s); // now I saved it to file!

var o = File.recall("item", "");
item = Deserialize(o);

item.swing(); // prints "Did 7 damage!"
item instanceof Item // returns true


This is great for games where the inventory changes and the items must each be saved. Or other properties such as player stats, and world variables, etc. Have fun!

(edited for proper highlighting ~neo)
  • Last Edit: March 25, 2013, 06:14:18 pm by N E O
If you use code to help you code you can use less code to code. Also, I have approximate knowledge of many things.

Sphere-sfml here
Sphere Studio editor here

Re: [code] Object Serialization
Reply #1
Code: (javascript) [Select]

var f = new Function("return new " + o.zztype + "();");
var obj = f();


Seems like it should just be

Code: (javascript) [Select]

var obj = global[o.zztype]();


Other than that this looks good. Unfortunately it doesn't look like it will handle cyclic data structures very well. OTOH, the one time I did have to save a cyclic data structure, it was easier just to make it non-cyclic....

Are you planning some sort of binary format, for instance to make save files harder to modify?

(edited for proper highlighting ~neo)
  • Last Edit: March 25, 2013, 06:16:15 pm by N E O

  • N E O
  • [*][*][*][*][*]
  • Administrator
  • Senior Administrator
Re: [code] Object Serialization
Reply #2
Whoops, looks like I didn't add syntax highlighting back to the forums yet; will fix that shortly.

  • Radnen
  • [*][*][*][*][*]
  • Senior Staff
  • Wise Warrior
Re: [code] Object Serialization
Reply #3

Code: [Select]

var f = new Function("return new " + o.zztype + "();");
var obj = f();


Seems like it should just be

Code: [Select]

var obj = global[o.zztype]();



That's quite nifty!

Edit: It doesn't work in Sphere. 'global' is not defined. I did some digging and found that the only way to access the global scope is by calling 'this' while in the global scope. So I changed the code to:

Code: [Select]

var obj = new this[o.zztype]();


It can be still a little dangerous if the environment does have that object in the global scope, I'll have to add a small check there first. And you are right about cyclic structures, but I don't use them often, and they aren't usually used for the kind of data that is intended to be saved, even though there might possibly a reason somewhere down the line.


Are you planning some sort of binary format, for instance to make save files harder to modify?


Not really, my plan was to add an encode/decode layer to the final output string/bytearray.
  • Last Edit: March 25, 2013, 02:56:52 pm by Radnen
If you use code to help you code you can use less code to code. Also, I have approximate knowledge of many things.

Sphere-sfml here
Sphere Studio editor here

  • N E O
  • [*][*][*][*][*]
  • Administrator
  • Senior Administrator
Re: [code] Object Serialization
Reply #4
Added syntax highlighting mod; use [ code=javascript ] [ /code ] (with no spaces) for JS highlighting.

Re: [code] Object Serialization
Reply #5

Edit: It doesn't work in Sphere. 'global' is not defined. I did some digging and found that the only way to access the global scope is by calling 'this' while in the global scope. So I changed the code to:

Code: [Select]

var obj = new this[o.zztype]();


Whoops, sorry! I generally use a small CommonJS wrapper (so I can have a bit more control than simply RequireScript) which injects the global object as global for me. Yeah, this is what you want, or save the global object in a closure or something.

Quote

And you are right about cyclic structures, but I don't use them often, and they aren't usually used for the kind of data that is intended to be saved, even though there might possibly a reason somewhere down the line.

I did have a legitimate reason for saving a cyclic structure once, but refactoring my code so that it wasn't cyclic was easier than extending my save system, so I think you're OK. :P

Quote

Not really, my plan was to add an encode/decode layer to the final output string/bytearray.

I'm going to write a MessagePack implementation for Sphere; you could possibly use it for that.

  • Radnen
  • [*][*][*][*][*]
  • Senior Staff
  • Wise Warrior
Re: [code] Object Serialization
Reply #6
One last note, the serialization here is just basic. I've since added the ability to serialize arrays. For those intreested it can be checked out on the github page: here.

Edit (below): thanks!
  • Last Edit: March 26, 2013, 12:17:09 am by Radnen
If you use code to help you code you can use less code to code. Also, I have approximate knowledge of many things.

Sphere-sfml here
Sphere Studio editor here

Re: [code] Object Serialization
Reply #7
Extra GitHub trick: The #L part of the URL can take a range of lines, so #L43-60 highlights lines 43 to 60, inclusive.