Saving gamedata

Started by
15 comments, last by BeerNutts 13 years, 3 months ago
I have a game that operates on a 3dtilemap. I need to be able to save the
data in the tilemap to a file and read it back in when the game
relaunches. I pasted the code below of the defines so you can see what
type of data I am dealing with.

The game is seperated into Chunks and each chunk having the 16x16x16 array.


struct Block
{
bool exists;
int tx,ty;
};

Block space[16][16][16];


Below is something that I have conjured up and It works, but there
has got to be a better way. Also each individual save file turns out to be
about 25kb kinda large where there will be 1000's of files.

Would binary writing be alot better for this?

Got to be a way to just copy the whole array to a file rather then what i'm
doing. I assume it would also be easier to read.

Hope someone has an idea.
Thanks in advance,
this has stumped me about a week.


void file::write(int x,int y,int z)
{
/*stringstream xStr,yStr,zStr;
if (x<100)
{
if (x<10)
{
xStr<<"0";
}
xStr<<"0";
}
xStr << x;
if (y<100)
{
if (y<10)
{
yStr<<"0";
}
yStr<<"0";
}
yStr << y;
if (z<100)
{
if (z<10)
{
zStr<<"0";
}
zStr<<"0";
}
zStr << z;*/
name.str(std::string());
//name << "save/" << x << "/" << y << "/" << z << ".txt";
//name << "save/" << xStr.str() << "x" << yStr.str() << "x" << zStr.str() << ".txt";
name << "save/" << x << "x" << y << "x" << z << ".txt";
temp = name.str();
fileStream.open(temp.c_str());
if (fileStream.is_open())
{
/*for (int i=100;i>=0;i-=2)
{
fileStream << i << endl;
}
cout << "Wrote " << temp.c_str() << "\n";*/
for (int tz=0;tz<16;tz++)
{
for (int ty=0;ty<16;ty++)
{
for (int tx=0;tx<16;tx++)
{
fileStream << Map->Chunk[x][y]->space[tx][ty][tz].tx;
fileStream << "\n";
fileStream << Map->Chunk[x][y]->space[tx][ty][tz].ty;
fileStream << "\n";
}
}
//fileStream << "\n";
}
}
else
{
//printf("/!\\ Cannot open \n");
cout << "/!\\ Cannot open " << temp.c_str() << "\n";
}
fileStream.close();
return;
}
If this post was helpful please +1 or like it !

Webstrand
Advertisement
Two ints and a bool on a typical system will be, for example, 32+32+8, multiplied by your chunk of 16*16*16 would be 294912 bytes by my reckoning, so I doubt a binary file is going to save much space - if the majority of the numbers in your ints are below 1000, it could possibly be even bigger (e.g. 12 in text will be 2 bytes, but 12 in 32-bit binary will still be 4 bytes).

However, these are not really concerning file sizes for PC storage.

If you really need to save space, might be easier to run the files through a pre-tested compressor and de-compress as needed at runtime.

Two ints and a bool on a typical system will be, for example, 32+32+8, multiplied by your chunk of 16*16*16 would be 294912 bytes by my reckoning, so I doubt a binary file is going to save much space - if the majority of the numbers in your ints are below 1000, it could possibly be even bigger (e.g. 12 in text will be 2 bytes, but 12 in 32-bit binary will still be 4 bytes).

However, these are not really concerning file sizes for PC storage.

If you really need to save space, might be easier to run the files through a pre-tested compressor and de-compress as needed at runtime.


Space is a concern, but not my main concern. Thanks for the information though :D
Is there a easier way to write this to a file then what I am doing?
If this post was helpful please +1 or like it !

Webstrand
What's the actual code you're using, sans commented-out chunks of cruft?

Of the stuff you posted, most of it seems questionable at best - but it's also marked out, so I have no way of knowing what your intentions are as far as how the code is meant to work and what's supposed to be there vs. not.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]


Two ints and a bool on a typical system will be, for example, 32+32+8, multiplied by your chunk of 16*16*16 would be 294912 bytes by my reckoning
294912 bits; that's 36 864 bytes. Still larger, but not an order of magnitude larger. The main benefit of saving things in a binary format though would be that it'd be quite a bit faster to load and save. Reading and writing ints in text mode is basically running your data through itoa/atoi every time. Of course, if there's a possibility that the code in question is going to run on systems with different endianness then you have to take that into account but that's not going to be slower than reading/writing in text mode (which has similar issues with line endings.)

'Aardvajk' said:

Two ints and a bool on a typical system will be, for example, 32+32+8, multiplied by your chunk of 16*16*16 would be 294912 bytes by my reckoning
294912 bits; that's 36 864 bytes. Still larger, but not an order of magnitude larger. The main benefit of saving things in a binary format though would be that it'd be quite a bit faster to load and save. Reading and writing ints in text mode is basically running your data through itoa/atoi every time. Of course, if there's a possibility that the code in question is going to run on systems with different endianness then you have to take that into account but that's not going to be slower than reading/writing in text mode (which has similar issues with line endings.)


Doh! Quite correct of course. Silly old me.
[font=&quot;CourierNew, monospace&quot;]struct Block { bool exists; int tx,ty; }; Block space[16][16][16];<br /> [font=&quot;CourierNew, monospace&quot;] <br /> [font=&quot;CourierNew, monospace&quot;] <br /> [font=&quot;CourierNew, monospace&quot;]Well, what are the max and min the tx and ty value could be? (f it&#39;s for a typical screen coordinate, can you get away with limiting tx and ty to 2048? If so, you can squeeze one Block into 3 bytes by writing 1 bit for the bool and 11 bits for x and y each, [font=&quot;CourierNew, monospace&quot;]which would be 16*16*16*2= 12288 bytes per space[][][][font=&quot;CourierNew, monospace&quot;]. So, you&#39;d call some kind of convert function for each space[][][], which would do this:<br /> [font=&quot;CourierNew, monospace&quot;] [font=&quot;Courier New&quot;]unsigned char *ConvertToSaveBlock(Block space[][][])<br /> {<br /> unsigned char *pStoreMemory;<br /> unsigned char *pLoc;<br /> pStoreMemory = malloc(3*16*16*16);<br /> pLoc = pStoreMemory;<br /> <br /> for (int i = 0; i &lt; 16; i++)<br /> {<br /> for (int j = 0; j &lt; 16; j++)<br /> {<br /> for (int k = 0; k &lt; 16; k++)<br /> {<br /> /* store the exists bit at the left *.<br /> *pLoc = (space<span style="font-weight:bold;">[j][k].exists ? (1 &lt;&lt; 7) : 0);<br /> /* store high 7 bits of 11 from tx in rest of byte */<br /> *pLoc |= (unsigned char)((space<span style="font-weight:bold;">[j][k].tx &amp; 0x7F0) &gt;&gt; 4);<br /> pLoc++;<br /> /* store low 4 bits of 11 from tx in top of next byte */ <br /> [font=&quot;Courier New&quot;]*pLoc = (unsigned char)((space<span style="font-weight:bold;">[j][k].tx &amp; 0xF) &lt;&lt; 4);<br /> /* store high 4 bits of 11 from ty in rest of byte */ <br /> [font=&quot;Courier New&quot;]*pLoc |= (unsigned char)((space<span style="font-weight:bold;">[j][k].tY &amp; 0x780) &gt;&gt; 7); <br /> [font=&quot;Courier New&quot;]pLoc++;<br /> /* store low 7 bits of 11 from tx in last byte */ <br /> [font=&quot;Courier New&quot;]*pLoc = (unsigned char)(space<span style="font-weight:bold;">[j][k].tx &amp; 0x7F); <br /> [font=&quot;Courier New&quot;]} <br /> [font=&quot;Courier New&quot;]} <br /> [font=&quot;Courier New&quot;]} <br /> [font=&quot;Courier New&quot;] return pStoreMemory;<br /> <br /> }<br /> <br /> //And you could do something like this:<br /> unsigned char *pCompressedMem = ConvertToSaveBlock(space);<br /> fwrite(pCompressedMem, 1, 16*16*16*3, fOutputFile);<br /> [font=&quot;CourierNew, monospace&quot;] [font=&quot;CourierNew, monospace&quot;] <br /> [font=&quot;CourierNew, monospace&quot;][font=&quot;CourierNew, monospace&quot;][size=&quot;4&quot;]Edit: Frigging new gamedev screwed up my post majorly, O well.<br /> [font=&quot;CourierNew, monospace&quot;] <br /> [font=&quot;CourierNew, monospace&quot;]

My Gamedev Journal: 2D Game Making, the Easy Way

---(Old Blog, still has good info): 2dGameMaking
-----
"No one ever posts on that message board; it's too crowded." - Yoga Berra (sorta)

Thanks for the responces!
I am still working on this, my internet has been down though what a drag.

Anyway, did I copy this correctly?

unsigned char *file::write2(Block space[][][])
{
unsigned char *pStoreMemory;
unsigned char *pLoc;
pStoreMemory = malloc(3*16*16*16);
pLoc = pStoreMemory;
for (int i = 0; i < 16; i++)
{
for (int j = 0; j < 16; j++)
{
for (int k = 0; k < 16; k++)
{
/* store the exists bit at the left *.
*pLoc = (space[j][k].exists ? (1 << 7) : 0);
/* store high 7 bits of 11 from tx in rest of byte */
*pLoc |= (unsigned char)((space[j][k].tx & 0x7F0) >> 4);
pLoc++;
/* store low 4 bits of 11 from tx in top of next byte */
*pLoc = (unsigned char)((space[j][k].tx & 0xF) << 4);
/* store high 4 bits of 11 from ty in rest of byte */
*pLoc |= (unsigned char)((space[j][k].tY & 0x780) >> 7);
pLoc++;
/* store low 7 bits of 11 from tx in last byte */
*pLoc = (unsigned char)(space[j][k].tx & 0x7F);
}
}
}
return pStoreMemory;
}


I am getting quite a few Errors:

declaration of `space' as multidimensional array must have bounds for all dimensions except the first
declaration of `space' as multidimensional array must have bounds for all dimensions except the first
In member function `unsigned char* file::write2()':
invalid conversion from `void*' to `unsigned char*'
`space' undeclared (first use this function)
(Each undeclared identifier is reported only once for each function it appears in.)

HERE is a picture with Line Numbers, a lot more helpful.
[attachment=1003:err1.png]
If this post was helpful please +1 or like it !

Webstrand
Have all the errors but this one fixed now:
53 file.cpp invalid conversion from `void*' to `unsigned char*'
Code:
53 pStoreMemory = malloc(3*16*16*16);
If this post was helpful please +1 or like it !

Webstrand

Have all the errors but this one fixed now:
53 file.cpp invalid conversion from `void*' to `unsigned char*'

Code:
53 pStoreMemory = malloc(3*16*16*16);


You should be able to cast to (unsigned char*) and make the warning go away... But this is C++; why not use new?

This topic is closed to new replies.

Advertisement