So far I've been dumping object serializations and loading them directly from that format. This brings me to a problem: Once a game goes out of production using this they'd have trouble making changes to object structure, i.e. multiple versions, without losing the original data. This problem extends to more areas than just objects in game. It's also player files, etc etc.

So my question is how do you guys suggest handling this? Any version system seems like it's going to be ugly, but it sounds like a feature that will be useful for post production games.

Wait, didn't this get discussed recently…? In any case, I think the conclusion was (a) save data, not objects, and (b) use a key:value system such that unrecognized keys in the save file are ignored by the object structure, and keys in the object structure with no corresponding value in the save file get some sane default.

Wait, didn't this get discussed recently…? In any case, I think the conclusion was (a) save data, not objects, and (b) use a key:value system such that unrecognized keys in the save file are ignored by the object structure, and keys in the object structure with no corresponding value in the save file get some sane default.

If you are using Ruby and Yaml then whats the problem?I mean, if you are removing a bunch of stuff from your objects then sure, I can see that.But if you use the ||= idiom for values during initialization you can conditionallyset your default values to nil or what have you. Worst case scenario you would have to add a thing or twoto old files, but with a simple version value this could be done pretty easily.

If you are using Ruby and Yaml then whats the problem?I mean, if you are removing a bunch of stuff from your objects then sure, I can see that.But if you use the ||= idiom for values during initialization you can conditionallyset your default values to nil or what have you. Worst case scenario you would have to add a thing or twoto old files, but with a simple version value this could be done pretty easily.

I'm not really convinced that it's safe or flexible post production, but I'll put some thought into it.

The LpMUD people have tackled this problem. I'd suggest taking a look at the Gurba mudlib for DGD, or perhaps the Phantasmal mudlib (also for DGD). Those are both persistent worlds which have object managers to deal with on-the-fly updates to not only objects, but inheritance trees.

Essentially, you provide an upgraded hook that the object manager can call when an object is loaded, so you can write code to handle migration from the original to a new version. Once upgraded, it sets its version so a future call to upgraded becomes a no-op.

If you are using Ruby and Yaml then whats the problem?I mean, if you are removing a bunch of stuff from your objects then sure, I can see that.But if you use the ||= idiom for values during initialization you can conditionallyset your default values to nil or what have you. Worst case scenario you would have to add a thing or twoto old files, but with a simple version value this could be done pretty easily.

Well, I'll tell you a few problems I'm having with this approach. It's not flexible when it comes to dumping references as alternative data. I.e. you may not want to save it like the object is written in another place. You may just want to save the reference to the lookup. Also, there's a problem when you decide at some point down the road to save classes/merge classes/change your data structures. It specifically maps them to classes based on their constant name. Also, I find the way you must use conditional initialization unintuitive and a poor convention.

So the direction I believe I am going to go is making objects configurable with maps/hashes. This should make the data flexible to any changes in the future from version to version. Two basic methods can be defined for any object that needs to save. We could do Player#configure(map) and Player#make_configuration(map). Then we simply serialize the map of data and write it. Then when we load the map we check the version and do any conversions needed step by step to get it in compliance with the current version. Then we simply pass the map to Player#configure and all should be good. This gets rid of the ugly conditional initialization/forced call to the initializer.

For completeness, here's what I settled on straight from my documentation:

Quote

Each class may mix-in CORALMUD::FileIO to define the methods #configure and#gen_configure. #gen_configure will construct a map based on all instance variables by default. If #to_configure_propertiesis overloaded it should return an array of instance variables. #configure will take this map as an argument to initializeits variables. #configure allows you to overload #version_control and #data_transform_on_load which allows you to hookinto the way it translates the hash into variables. #gen_configure lets you overload #data_transform_on_save to accomplishthe same thing to transform the hash before it is returned.

The conditional init was something Tyche did in RocketMud which I found helpful. But I don't rememberclaiming it as my idea. I'm sure your idea will work just fine. It seems like a lot more work on the surface though.

Conditional initialization like that works well if you're only adding fields, and that these fields have reasonable defaults. If you ever find yourself renaming fields, you can easily lose information unless you have some kind of update hook, as has been mentioned.