Allegro.cc - Online Community

Allegro.cc Forums » Game Design & Concepts » fixing crashes, file sizes and array sizes.

This thread is locked; no one can reply to it. rss feed Print
fixing crashes, file sizes and array sizes.
jason perkins
Member #10,524
January 2009

Hi again. I'm approaching the end of my project. Before I try to figure out how to build a release version for it I'm attempting to fix all the scenarios that can cause the program to crash.

Most of these issues come from array sizes not matching files.

Currently if I load a map file that doesn't match the dimensions of my current vector<map> it will fail.

This is one of the solutions I've tried:

#SelectExpand
1 2file = al_fopen(a.c_str(), "r"); 3 4 if (al_fsize(file) == (map.getWidth()*map.getHeight())) 5 { 6 std::cout << "success!"; 7 8 for (int h = 0; h<map.getHeight(); h++) 9 { 10 for (int w = 0; w<map.getWidth(); w++) 11 { 12 map.map[h*map.getWidth()+w].setId(al_fread32le(file)); 13 map.map[h*map.getWidth()+w].setBmp(pallet.pallet[map.map[h*map.getWidth()+w].getId()].getBmp()); 14 } 15 } 16 17 al_fclose(file); 18 } 19 else 20 { 21 al_fclose(file); 22 std::cout << "File size does not match map size!\n"; 23 }

al_fsize(file) Does not equal the number of elements in my array. The manual isn't very clear on this, but I was assuming the al_fsize() gets the amount of data blocks in my file.

Now, the next thing I'm considering (if there is no way to get do this with the previous method).

When I save the map file, write the map's width, and height in the first 2 blocks of the file. Then create a map that size before loading. My issue with doing this is:

If someone wanted to use my map editor files in their own program, they'd have to know about thoes first two blocks of data.

I guess the question is.

Can I get by without adding array sizes to the files?

Is adding this extra data to the files a more practical solution for me and people that are potentually using them?

Matthew Leverton
Supreme Loser
January 1999
avatar

Every call to writing a 32-bit integer increases the file size by 4 bytes. So your file size will be w * h * 4 (assuming you write one integer per cell). I'm not sure where you are storing the dimensions right now, but a file size of 16 "blocks" (i.e., one block = 4 bytes in this example) could be 4x4 or 8x2 or 16x1, etc. That is, you cannot deduce the width and height by only the total size.

Regardless of that, I would generally store the dimensions at the beginning.

jason perkins
Member #10,524
January 2009

Thanks alot, That's definately enough for me to get this working. I guess If someone where to use it. I'd include a readme to tell them exactly how the files are made and how to access the information. So the first two blocks identifying the width/height wouldn't be much of an issue.

LennyLen
Member #5,313
December 2004
avatar

I like to have a header for the map file that contains as much info as possible about the file.

I store the data it will write in a struct like this one:

typedef struct {

    char ident[4];
    uint32_t width;
    uint32_t height;
    uint32_t num_tiles;
    uint32_t bytes_per_tile;
    uint32_t tile_data_length;
    uint32_t tile_data_offset;


} mapfile_header;

ident is a unique string (in this case, TMAP), that can be used to identify that a file being read is of the correct type. width and height are pretty self-explanatory. The number of tiles doesn't really need to be stored, since it can be easily calculated from the width and height, but I like to store it anyway. To increase the flexibility of the format, I store the number of bytes per tile. If a map has simple needs, a single char per tile may do, for complicated maps with layers, and many different tiles, each record could take up several bytes. tile_data_length will be equal to num_tiles * bytes_per_tile but I again store it for use later. tile_data_offset stores the location in the file where the tile data starts. This means we can add any amount of extra comments or data between the header and the tile data if we want to later.

You can check the sizes as you load it like this (test map using one byte per tile):

#SelectExpand
1int load_map() { 2 3 int x, y; 4 PACKFILE *in = pack_fopen("test.map", F_READ); 5 if (!in) { 6 7 allegro_message("Error opening map file!"); 8 return -1; 9 10 } 11 12 pack_fread(header.ident, 4, in); 13 if (strncmp(header.ident, "TMAP", 4) != 0) { 14 15 allegro_message("Inalid file!"); 16 return -1; 17 18 } 19 header.width = pack_igetl(in); 20 if (header.width != map.getWidth()) {} 21 22 allegro_message("Map width in header does not match!"); 23 return -1; 24 25 } 26 header.height = pack_igetl(in); 27 if (header.height != map.getHeight()) {} 28 29 allegro_message("Map height in header does not match!"); 30 return -1; 31 32 } 33 header.num_tiles = pack_igetl(in); 34 if (header.num_tiles != map.getWidth() * map.getHeight()) {} 35 36 allegro_message("Map size in header does not match!"); 37 return -1; 38 39 } 40 header.bytes_per_tile = pack_igetl(in); 41 if (header.bytes_per_tile != sizeof(uint8_t)) { 42 43 allegro_message("Tile size in header does not match!"); 44 return -1; 45 46 } 47 header.tile_data_length = pack_igetl(in); 48 if (header.tile_data_length != sizeof(uint8_t) * map.getWidth() * map.getHeight()) { 49 50 allegro_message("Tile data size in header does not match!"); 51 return -1; 52 53 } 54 header.tile_data_offset = pack_igetl(in); 55 56 for (y = 0; y < TILES_H; y++) { 57 58 for (x = 0; x < TILES_W; x++) { 59 60 tilemap[x][y] = pack_getc(in); 61 62 63 } 64 65 } 66 67 pack_fclose(in); 68 return 0; 69 70}

edit: you'd need to convert that from A4 to A5, but that is pretty trivial.

jason perkins
Member #10,524
January 2009

Thanks Lenny, That looks very useful. Right now though the program isn't going to know in advance what sizes of files to expect. It's just for loading any file that was created by the same program. That looks like a solid system though. And once I start making maps I intend to use I'll probly come back and snag this code. :)

I could have just mis-understood something, but it seems to me like that sort of system is used after you've made a file, to make certain you're loading the correct data from it.

Neil Roy
Member #2,229
April 2002
avatar

Something else I always add to my map header is a version number. So if you modify your map data in the future, you can update the version number so that old maps that were made using the old structure aren't loaded. You could also easily create a converter to convert your maps from the old version to the new one (something I done a couple times with my Deluxe Pacman game). So basically I had the header + version number as the first two pieces of data.

Go to: