Archived

This topic is now archived and is closed to further replies.

afults

Newbie question: Saving Files? (C++)

Recommended Posts

Can anyone tell me, or point me in the direction of a tutoral, how to allow file saving so the player can continue playing where they left off after the program is shut down. Edited by - afults on March 18, 2002 8:10:50 PM

Share this post


Link to post
Share on other sites
well, as i know, as long as you know how to to open and write to a file and later on read it, you already know how to save your a game,

Share this post


Link to post
Share on other sites
You will need to use get,seek,put,tell etc. that are included in fstream.h
Sorry if this isn''t much help but I haven''t used them in a while myself. I''ll find some of my old code tonight and post it tomorrow.

Share this post


Link to post
Share on other sites
This question is more complex than it seems. Answering it in full is the work of a reasonably detailed article, but I''ll give you a quick primer.

Say you''ve written the game and you wish to save the game state. The first thing you need to do is decide on a format. For the smallest possible data file, the format will need to be relatively fixed, with the variable portions being declared in a header. For less demanding applications, numerous solutions exist. We''ll consider the less demanding solutions first.

Simple Text Files
Open/create a file and throw the values in, in some specified order. Read them back out in the same order. Dirty, quick, but you''re done and home before dinner''s cold.

void WriteStateToFile(GameState & gs, std::string filename)
{
std::ofstream fout;
fout.open( filename.c_str() );
if(fout.fail())
return; // in production code I would throw and exception...
fout << gs.prop1 << ''\n''
<< gs.prop2 << ''\n''
...
<< gs.propN << endl;
fout.close();
}

To read, use ifstream instead of ofstream and >> instead of << (I''d also suggest renaming the variable to fin or something like that).

INI File-Style
Windows has a bunch of functions for dealing with initialization (.ini) files, a holdover (at least to Microsoft) from the 16-bit Windows days, before there was the registry. In those days, every application that wanted to maintain information between sessions wrote them to an .ini file, which was structured like so:

[SectionName1]
S1VariableName1=S1Value1
S1VariableName2=S1Value2
...
S1VariableNameN=S1ValueN

[SectionName2]
S2VariableName1=S2Value1
S2VariableName2=S2Value2
...
S2VariableNameN=S2ValueN
...

You were free to use any names for SectionName# and *VariableName#; I just named them so to illustrate the fact that they had to be unique within their section. You wrote values to .ini files using Write[Private]ProfileSection, Write[Private]ProfileString and Write[Private]ProfileStruct. Reading data was a question of using the Get* complements of these functions. The [] denotes optional; there are not "private" versions of these functions.

You can either use the Windows .ini functions (if you''re writing for Windows), or you can emulate them using C++. The cool thing about the .ini file functions is that they''re first cousins (more like siblings, actually) of Registry functions that are nearly identical in function, but have fairly different names.

Here''s some C++ code that works in similar fashion.

  
#include <ifstream>

#include <iostream>

#include <string>

using std::endl;
using std::fstream;
using std::string;
void WriteDataValue(fstream fout, string section, string key, string value)
{
size_t pos = 0;
string str, scmp = "[" + section + "]";
string buf;
//

// find the section

fout.clear(); // clear failbits, if any

fout.seek(ios::beg);
while(!fout.eof())
{
getline(fout, str);
if(str == scmp) // found the section

break;
buf += (str + "\n"); // append data to buffer

}
//

// find the key

while(!fout.eof())
{
fout >> str;
if( str == key )
break;
}
//

// okay, we''ve found the position to insert our value

buf += ("=" + value + "\n");
//

// now get the rest of the file

while(!fout.eof())
{
getline(fout, str);
buf += (str + "\n");
}
//

// now write the whole thing back to the file in one fell swoop

fout << buf;
}

Ugh! Why was that so nasty?

C++ I/O doesn''t support insertion into files, so you have to read the data out into a buffer, modify it in the middle and then write it all back out. For the above procedure to work, the fstream must have been opened with ios::in|ios::out (read/write/no append).

Well, that''s probably overkill (and ugly, and inefficient). And it doesn''t buy you much. So what other options do I have?

Binary Savegame Files
Ok, this is where things get grimy (enter Noreaga beat...).

A full discussion of implementing a binary savegame format would, frankly, scare you, so I''ll simply discuss the theory.

First, you decide on a format. This is a conceptual layout of how the file will be structured, and might contain info to allow a single file represent several games by the same player, etc. You''ll need a file header which will contain information about the data in the file itself. Headers are usually at the top (head) of the file, and are always of fixed size. They may contain values that indicate the sizes of various other portions of the data.

Next, you''ll need a data layout - how the actual game data is stored. Depending on how large/complex your game is, this might be fairly involved. You might also want to consider using a chunk-based format, where individual chunks can easily be read from and written to disk.

Finally, you''ll need to actually write the code, and note that this must be done in binary mode. In this mode, Windows will not convert your newlines or any other special characters but will "dump" the binary equivalent of your data to file.


That''s it, in brief. Hopefully you can now make an informed decision - and maybe even implement your own simple savegame files. Good luck!

[ GDNet Start Here | GDNet Search Tool | GDNet FAQ | MS RTFM [MSDN] | SGI STL Docs | Google! ]
Thanks to Kylotan for the idea!

Share this post


Link to post
Share on other sites
quote:
Original post by elis-cool
how do you get into binary mode, I thought you could not do stright binary in C++ but instead had to go through hex...

Use mode ios_base::binary.

This also pointed out to me that I used the old mode bit. To be Standard Compliant, your code should use ios_base::in and ios_base::out, not ios::in and ios::out.


[ GDNet Start Here | GDNet Search Tool | GDNet FAQ | MS RTFM [MSDN] | SGI STL Docs | Google! ]
Thanks to Kylotan for the idea!

Share this post


Link to post
Share on other sites
Try reading my filemapping tutorial. It will help you with the file access functions specific of Windows.

What you''ll need to write in the files, are the data you''d need to make the game start from the same place where it was saved, the next time you load it.


--DK
--H. Hernán Moraldo
http://www.hhm.com.ar/
Sign up to the HHM''s developers'' newsletter.

Share this post


Link to post
Share on other sites
WOW! Thanks I think I finally get it, now all those weeks I spent trying to understand this finally has produced some results. I think I can figure the rest out on my own. THANK YOU so very much!

Share this post


Link to post
Share on other sites