0

I just learned about the i/o part of the STL, more specifically fstream. Although I can now save binary info and classes I've made to the hard drive, I am not sure how to define how the info should be read.

I saw the answer for making a file format from this post:

Typically you would define a lot of records/structures, such as BITMAPINFOHEADER, and specify in what order they should come, how they should be nestled, and you might need to write a lot of indices and look-up tables. Such files consists of a number of records (maybe nestled), look-up tables, magic words (indicating structure begin, structures end, etc.) and strings in a custom-defined format.

What I want to know specifically is how to do this with the STL and C++... Since the format is meant simply for the use of a game I would think it would be much easier though. The format should:

  • Be traversable (I can look through it and find the start of structure and maybe check its name
  • Be able to hold multiple classes and data in a single file
  • Have identifiable starts and ends to sections: such as the space in text files
  • Maybe have it's own icon to represent it??

How do I do this in c++ ?

Community
  • 1
  • 1
Griffin
  • 2,399
  • 7
  • 48
  • 83
  • 1
    I would suggest boost, take a look at this http://www.boost.org/doc/libs/1_47_0/libs/serialization/doc/tutorial.html – HRÓÐÓLFR Jul 22 '11 at 23:46
  • I'm not sure what you are trying to achieve. You either write your complete state to the file and read back to restore all classes (e.g. boost::serialize), in which case I don't understand your listed requirements; or you use memory mapped file (e.g., boost::interprocess) and keep your classes persistent. I don't think you want to get into situation "manually" searching and parsing your files. – Gene Bushuyev Jul 22 '11 at 23:54
  • 1
    The process you're attempting is called serialization, and the standard library really doesn't help you in that regard. I'd look for other libraries. – Mark Ransom Jul 22 '11 at 23:54
  • Stop, stop, stop! What do you really need to save here? Spend time to think this through so you don't make this problem more complicated than needed. For example, is it maybe enough to save points, which weapons you have, how long you played, and which level you are on? Then Boost serialization is extremely overkill. Indeed, it is probably enough to use normal POSIX C IO functions. Or, if you want something more safe, use some kind of database (maybe SQLite?)... – Johan Kotlinski Jul 23 '11 at 00:25
  • Hmm, maybe a generic answer and I don't expect you to accept it as answer, but for me the book "Golden Rules of Gameprogramming" by Martin Brownlow answered a lot of questions. And it has also a topic for serialization and its problem. I really want to recommend you that book. It also covers other topics. Hope this comment is a bit useful :). Here is another topic which covers this: http://gamedev.stackexchange.com/questions/2269/what-are-good-solutions-for-serialization-in-c –  Jul 23 '11 at 00:33
  • @kotlinksi Would it be useful to start with Boost serialization anyway for more complicated games later? I'm hoping to one day save randomly generated worlds along with what you stated. – Griffin Jul 23 '11 at 01:46

1 Answers1

3

The first stage in determining how to structure your save-file is determining what information needs to be stored. Presumably, you have a list of entities, each of which with generic information (probably derived from one of a few base classes), such as position, velocity etc.

One of the best things you can do to implement a map format is to have a save-parser for each class (some can just derive from the base class' save-parser). So for instance, if you have a player class, which derives from CBaseNPC, you could most-likely simply derive from CBaseNPC, override the parser, calling the base-class function, and adding any other necessary fields, for example, if we had (pseudocode):

void CBaseNPC::Save() {
     SaveToFile( health );
     SaveToFile( armor );
     SaveToFile( weapons );
     SaveToFile( position );
     SaveToFile( angles );
}

Then for your player class:

void CPlayer::Save() {
     CBaseNPC::Save();
     SaveToFile( achievement_progress );
}

Obviously, this is just a simple example, and no doubt your saving parsers will have more fields etc. to deal with.

Dealing with the structure of the file itself, the main thing you need to worry about is delimiters, how will your main load-parser recognise what each field corresponds to?

I suppose the best way to explain this would be with an example, the following could be a simple start to a save-file:

Map: {mapname}
Gametime: {gametime}

===Player===
Health: {health}
Armor: {armor}
Weapons: {wep1 (wep1Ammo), wep2 (wep2Ammo), wep3 (wep3Ammo)}
Position: {x, y, z}
Angles: {yaw, pitch, roll} // Could be quaternion instead.
AchievementProgress: {arbritraryData}
===Player===

===NPC-npc_name===
Health: {health}
Armor: {armor}
Weapons: {wep1 (wep1Ammo), wep2 (wep2Ammo), wep3 (wep3Ammo)}
Position: {x, y, z}
Angles: {yaw, pitch, roll} // Could be quaternion instead.
===NPC-npc_name===

===Entity-item_name===
Position: {x, y, z}
Angles: {yaw, pitch, roll}
Model: {modelname}
===Entity-item_name===

Here we have used the "===" string as a delimiter for the start of a class's parameters, and a new line as the delimiter for the parameters within each class.

It is then a relatively simple matter of structuring your parser so it reads in the map name, and loads it. Then sets the game-time to the value specified in the save-file.

It then looks through the file until it finds a "===" reads the string it encounters, and looks it up from a dictionary (possibly an std::map or std::unordered_map) to determine the class to create (or edit) with the information in the file. Once it has determined the class type, it can then proceed to call the Load() function from that class, which will retrieve all the information contained. The parser then looks for the next instance of the "==={string encountered}===" and closes that class. It then proceeds following the same procedure with the next class encountered.

Sorry for the length of this post, and I'm sure it could be made briefer and there are probably some things I have missed, I just wrote this off the top of my head, so there may be erroneous things here, but I hope it puts you on the right path to getting a workable save-file format. :)

If you still have any problems or questions regarding my post, please comment, I'll do my best to answer promptly.

Thomas Russell
  • 5,870
  • 4
  • 33
  • 68