Save Data Handling in Shipyard

Published November 24, 2013
Advertisement
When I first added the ability to save ship designs, the system I used was, to put it bluntly, not very good. The format it used was just a text file, and loading relied heavily on things like line breaks. When opened in a text editor, it looked like this, only longer:[code=nocode:0]name:Light Cargosystem:0:7:4system:1:7:6system:3:7:9system:9:6:4system:9:6:5system:9:5:5system:9:5:4weapon:2:10:6:2weapon:2:10:8:2weapon:2:10:10:2weapon:2:10:12:2weapon:2:6:6:6weapon:2:6:8:6weapon:2:6:10:6weapon:2:6:12:6tile:28:5:4tile:32:5:5tile:4:5:6tile:4:5:7tile:4:5:8tile:4:5:9tile:4:5:10tile:4:5:11tile:4:5:12tile:1:6:4
Basically, the game would read one line at a time, split the string at every occurrence of a colon, and look at the pieces. If the first string was "system," it would look for three integers: an ID corresponding to the system type, an x coordinate, and a y coordinate. Tiles and weapons were much the same, except the latter had a fourth value for the direction in which it was aimed.

It worked well enough fat the time, but I think you can see why I had to change it. First, it wasn't expandable. Sure, I could add a new named series of integers for different ship parts, but I would have had to recode it entirely from scratch to work with, for example, a full world save. It didn't provide any sort of standardized framework, only a simple system for a single job. Second, it was generally clunky. There was no organization, and designs were loaded in real time as the file was read. This meant that there was no "middleman" where data could be both saved and retrieved, without having to constantly open new input and output streams.

This had to be remedied before I could work on world saving, so I set out to create a new system which presented a standardized file format that could be re-used for anything I needed to save. The first thing I did was switch from plain text to binary, under the assumption that it would be more efficient. I don't have any evidence as to the truth of that, but seems to make more sense to save, say, a numerical value in binary rather than the characters that make up the number.

I also wanted it to be organized--no more making lists of things and relying on the order. I wanted every data point to have a name, and the ability to put related data into groups. Basing my new system off my experience modding Minecraft (which isn't known for technical efficiency, but hey, it's all I know), I created what I call the "data tree" system.

A data tree can store any of Java's basic data types, and more importantly another data tree. By nesting data trees within data trees, related data could be grouped together. This is where the system gets its name--a diagram of a data tree would look somewhat like an actual tree, with every branch being a new subgroup of data. When writing to a file, every piece of data is saved with its name, value, and type, so that when reading it back into the system it can be properly parsed without having to assume that things will be in a certain order (like the old system did).

Once data is stored or loaded into a data tree, it is contained in a HashMap correlating its name to its value. The map stores everything as plain Objects, but there are methods called getInt(), getString(), getGroup(), etc. that cast the data to the proper type. This assumes the thing reading the data knows what type it is. However if that is not the case, there is a method called getGeneric() that returns a plain Object. From there, calling getClass() will allow the user to figure out what kind of data it is.

Replacing the ship saving system with data trees was easy. I needed a string for the name and sub-groups for systems, weapons, and decorations. The systems and weapons groups contained their own sub-groups, each with the data for an individual component of the ship. The decorations group was even simpler, only containing the coordinates and ID numbers of the decorative tiles that made up the outside of the ship. This was easy because systems and weapons are all a part of the same class, and are different only in the stats passed to them as arguments. World saving, however, was more difficult because different objects (with a lowercase "o," as opposed to Java Objects) had truly different behaviors, meaning they needed their own classes. After much thinking, I settled on a system by which each object class was assigned a numerical ID which was saved with the object. When the object's data was read back in, the game would find its class based on the ID saved with the object, then cast it to that class. I had to do a lot of crazy bollocks with Java reflections, but in the end I got a system that worked quite nicely.

If anyone is interested, I'd be happy to post the source code of the applicable classes. Until that happens, though, I'm omitting it just because this post is already much longer than I had planned.
2 likes 1 comments

Comments

Navyman

Glad that you are optimizing sections of your game early, especially something like the actual shipyard section. I developed a game that had a similar feature and the number comment group I had was about this, even it will it being a very minor section of the game. People like to design their own things and making sure that it work great is key to their happiest. :)

November 26, 2013 02:22 PM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Advertisement