Data Management
Hi everyone,
I'd like to be able to save data (consisting of either a large C struct or an array of C structs) to my computer's desktop from my cocoa editor program and then drag that file over to my iOS app's resource bundle. I find that with certain types of data this works but for other types it doesn't - I tried using both fread()/fwrite() as well as NSData and the results remained the same. Is this the result of some difference between architectures?
I'd like to be able to save data (consisting of either a large C struct or an array of C structs) to my computer's desktop from my cocoa editor program and then drag that file over to my iOS app's resource bundle. I find that with certain types of data this works but for other types it doesn't - I tried using both fread()/fwrite() as well as NSData and the results remained the same. Is this the result of some difference between architectures?
That's not very safe, but since ARM and x86 are both little-endian, it can be made to work with some care. I'd suggest adding assertions that sizeof(yourStruct) == whatYouExpect and offsetof(yourStruct, eachField) == whatYouExpect. Sticking to the [u]int[n]_t types from <stdint.h> + float/double and sorting the fields of your structs by size, largest first, will help too.
For maximum safety, serialize each primitive explicitly yourself.
For maximum safety, serialize each primitive explicitly yourself.
Thanks for the reply. So here's just one data struct from my game (which is by the way an open world style rpg so lots of data)....
...From what your telling me this was poor planning on my part
and trying to do what you describe to all of my data seems unrealistic especially considering that I'm not a great programmer and have little experience with really low-level C stuff.
Is there any way out of or around this without having to parse every single struct?
This is a shot in the dark, but might it be possible to reorder all of the structs' fields using bit fields in order to eliminate paddings?
Code:
typedef struct
{
rain_particle_t g_rain[MAX_RAIN_PARTICLES];
snow_particle_t g_snow[MAX_SNOW_PARTICLES];
time_interval_t g_weather_start_turn;
time_interval_t g_weather_end_turn;
time_interval_t g_weather_plateu_start_turn;
time_interval_t g_weather_plateu_end_turn;
float g_weather_intensity;
float g_curr_weather_intensity;
BOOL g_is_snow_active;
BOOL g_is_rain_active;
int g_particle_cnt;
BOOL g_is_lightning;
int lightning_timer;
cmbt_msg_t cmbt_msgs[MAX_CMBT_MSGS];
int cmbt_is_active;
int cmbt_player_ap;
int cmbt_bot_ap;
int cmbt_foe_idx_list[MAX_CMBT_FOES];
int cmbt_ally_idx_list[MAX_CMBT_ALLIES];
int cmbt_foe_cnt;
int cmbt_ally_cnt;
int cmbt_turn_type;
int cmbt_turn_idx;
int cmbt_end_turn_at_end_delay;
int cmbt_did_update_player_spell_ai;
int player_target_type;
int player_target_idx;
int player_readied_spell;
float player_target_alpha;
BOOL is_player_target_darkening;
int key_value_count;
time_interval_t tick_cnt;
time_interval_t turn_cnt;
player_t player;
object_t objects[MAX_OBJECTS];
container_t containers[MAX_CONTAINERS];
door_t doors[MAX_DOORS];
bot_t enemies[MAX_BOTS];
//bot_t npcs[MAX_NPCS];
item_t items[MAX_ITEMS];
item_t item_quick_slot[MAX_ITEM_QUICK_SLOTS];
light_t light_list[LIGHT_LIST_SIZE];
decal_t blood_decal_list[MAX_BLOOD_DECALS];
spell_effect_t spell_effects[MAX_WORLD_SPELL_EFFECTS];
shop_t shops[MAX_SHOPS];
int npc_cnt;
int container_cnt;
int item_cnt;
int portal_cnt;
int door_cnt;
int light_cnt;
int blood_decal_cnt;
int uniqueid_cntr;
int spell_quick_slots[MAX_SPELL_QUICK_SLOTS];
time_interval_t game_delay;
}game_state_t;...From what your telling me this was poor planning on my part

and trying to do what you describe to all of my data seems unrealistic especially considering that I'm not a great programmer and have little experience with really low-level C stuff.
Is there any way out of or around this without having to parse every single struct?
This is a shot in the dark, but might it be possible to reorder all of the structs' fields using bit fields in order to eliminate paddings?
bitfields will reduce portability even further.
There's nothing ridiculously bad about this struct. Replace "int" with "int32_t" (or smaller if you like); replace BOOL with uint8_t; ensure time_interval_t is a typedef off an explicitly sized type, and sort the fields big to small and it should start working... (and of course do the same to the nested struct types).
I really do suggest adding at least the sizeof() assertion though. Better to crash at startup when the assertion fails than corrupt memory or data later.
Doing this the right way is easy too, but verbose:
and similarly for deserialize. Then you just have to implement serialize_float, serialize_int, etc. portably.
There's nothing ridiculously bad about this struct. Replace "int" with "int32_t" (or smaller if you like); replace BOOL with uint8_t; ensure time_interval_t is a typedef off an explicitly sized type, and sort the fields big to small and it should start working... (and of course do the same to the nested struct types).
I really do suggest adding at least the sizeof() assertion though. Better to crash at startup when the assertion fails than corrupt memory or data later.
Doing this the right way is easy too, but verbose:
Code:
void serialize_game_state(stream_t stream, game_state_t const *state)
{
for (int i = 0; i < RAIN_PARTICLE_COUNT; ++i) serialize_rain_particle(stream, &(state->rain_particles[i]));
...
serialize_float(stream, g_weather_density);
serialize_int(stream, ...
}and similarly for deserialize. Then you just have to implement serialize_float, serialize_int, etc. portably.
Thanks OneSadCookie for all of your help.
So for simplicity's sake let's just say that I'm only saving game data from the OS app into the iOS app's docs directory. Should I be concerned about the future portability of this data (i.e. if apple changes the arm architecture in some way that somehow affects the memory mapping or whatever)? ...Or are there other concerns I'm missing? Also, how likely a scenario (the architectual change) do you personally think this is? I'm not adverse to gambling if I feel fairly certain (say 80%+) of its unlikelihood.
Thanks.
So for simplicity's sake let's just say that I'm only saving game data from the OS app into the iOS app's docs directory. Should I be concerned about the future portability of this data (i.e. if apple changes the arm architecture in some way that somehow affects the memory mapping or whatever)? ...Or are there other concerns I'm missing? Also, how likely a scenario (the architectual change) do you personally think this is? I'm not adverse to gambling if I feel fairly certain (say 80%+) of its unlikelihood.
Thanks.
You will always be able to write code to read whatever format you decide on now. Just be aware that taking the shortcut now does not necessarily mean you will get away without writing the hard code forever.
Also, always write a few sanity bytes and a version number at the start of each of your custom file formats. Makes it easy to change the format in the future, and to read multiple versions of the format.
Also, always write a few sanity bytes and a version number at the start of each of your custom file formats. Makes it easy to change the format in the future, and to read multiple versions of the format.
Possibly Related Threads...
| Thread: | Author | Replies: | Views: | Last Post | |
| Game State Management | Mattonaise | 6 | 6,129 |
Apr 16, 2011 10:18 AM Last Post: Mattonaise |
|
| iPhone memory management | mlady | 2 | 2,827 |
Mar 10, 2009 03:10 PM Last Post: mlady |
|

