store version info in progress file

This commit is contained in:
Andrei Alexeyev 2017-10-10 09:13:07 +03:00
parent 06a9874898
commit de246906e0
No known key found for this signature in database
GPG key ID: 363707CD4C7FE8A4
4 changed files with 80 additions and 12 deletions

View file

@ -10,6 +10,7 @@
#include "progress.h"
#include "stage.h"
#include "version.h"
/*
@ -48,6 +49,9 @@
- PCMD_GAME_SETTINGS
Sets the last picked difficulty, character and shot mode
- PCMD_GAME_VERSION
Sets the game version this file was last written with
*/
/*
@ -84,6 +88,20 @@ typedef struct UnknownCmd {
uint8_t *data;
} UnknownCmd;
static bool progress_read_verify_cmd_size(SDL_RWops *vfile, uint8_t cmd, uint16_t cmdsize, uint16_t expectsize) {
if(cmdsize == expectsize) {
return true;
}
log_warn("Command %x with bad size %u ignored", cmd, cmdsize);
if(SDL_RWseek(vfile, cmdsize, RW_SEEK_CUR) < 0) {
log_warn("SDL_RWseek() failed: %s", SDL_GetError());
}
return false;
}
static void progress_read(SDL_RWops *file) {
int64_t filesize = SDL_RWsize(file);
@ -131,6 +149,8 @@ static void progress_read(SDL_RWops *file) {
return;
}
TaiseiVersion version_info = { 0 };
while(SDL_RWtell(vfile) < bufsize) {
ProgfileCommand cmd = (int8_t)SDL_ReadU8(vfile);
uint16_t cur = 0;
@ -206,17 +226,24 @@ static void progress_read(SDL_RWops *file) {
break;
case PCMD_GAME_SETTINGS:
if(cmdsize == sizeof(uint8_t) * 3) {
if(progress_read_verify_cmd_size(vfile, cmd, cmdsize, sizeof(uint8_t) * 3)) {
progress.game_settings.difficulty = SDL_ReadU8(vfile);
progress.game_settings.character = SDL_ReadU8(vfile);
progress.game_settings.shotmode = SDL_ReadU8(vfile);
} else {
log_warn("Command %x with bad size %u ignored", cmd, cmdsize);
}
break;
while(cur < cmdsize) {
SDL_ReadU8(vfile);
cur += sizeof(uint8_t);
case PCMD_GAME_VERSION:
if(progress_read_verify_cmd_size(vfile, cmd, cmdsize, TAISEI_VERSION_SIZE)) {
if(version_info.major > 0) {
log_warn("Multiple version information entries in progress file");
}
size_t read __attribute__((unused)) = taisei_version_read(vfile, &version_info);
assert(read == TAISEI_VERSION_SIZE);
char *vstr = taisei_version_tostring(&version_info);
log_info("Progress file from Taisei v%s", vstr);
free(vstr);
}
break;
@ -233,6 +260,28 @@ static void progress_read(SDL_RWops *file) {
}
}
if(version_info.major == 0) {
log_warn("No version information in progress file, it's probably just old (Taisei v1.1, or an early pre-v1.2 development build)");
} else {
TaiseiVersion current_version;
TAISEI_VERSION_GET_CURRENT(&current_version);
int cmp = taisei_version_compare(&current_version, &version_info, VCMP_TWEAK);
if(cmp != 0) {
char *v_prog = taisei_version_tostring(&version_info);
char *v_game = taisei_version_tostring(&current_version);
if(cmp > 0) {
log_info("Progress file will be automatically upgraded from v%s to v%s upon saving", v_prog, v_game);
} else {
log_warn("Progress file will be automatically downgraded from v%s to v%s upon saving", v_prog, v_game);
}
free(v_prog);
free(v_game);
}
}
free(buf);
SDL_RWclose(vfile);
}
@ -494,6 +543,25 @@ static void progress_write_cmd_game_settings(SDL_RWops *vfile, void **arg) {
SDL_WriteU8(vfile, progress.game_settings.shotmode);
}
//
// PCMD_GAME_VERSION
//
static void progress_prepare_cmd_game_version(size_t *bufsize, void **arg) {
*bufsize += CMD_HEADER_SIZE + TAISEI_VERSION_SIZE;
}
static void progress_write_cmd_game_version(SDL_RWops *vfile, void **arg) {
SDL_WriteU8(vfile, PCMD_GAME_VERSION);
SDL_WriteLE16(vfile, TAISEI_VERSION_SIZE);
TaiseiVersion v;
TAISEI_VERSION_GET_CURRENT(&v);
// the buffer consistency check should fail later if there are any errors here
taisei_version_write(vfile, &v);
}
//
// Copy unhandled commands from the original file
//
@ -531,6 +599,7 @@ static void progress_write(SDL_RWops *file) {
SDL_RWwrite(file, progress_magic_bytes, 1, sizeof(progress_magic_bytes));
cmd_writer_t cmdtable[] = {
{progress_prepare_cmd_game_version, progress_write_cmd_game_version, NULL},
{progress_prepare_cmd_unlock_stages, progress_write_cmd_unlock_stages, NULL},
{progress_prepare_cmd_unlock_stages_with_difficulties, progress_write_cmd_unlock_stages_with_difficulties, NULL},
{progress_prepare_cmd_hiscore, progress_write_cmd_hiscore, NULL},

View file

@ -28,6 +28,7 @@ typedef enum ProgfileCommand {
PCMD_STAGE_PLAYINFO = 0x03,
PCMD_ENDINGS = 0x04,
PCMD_GAME_SETTINGS = 0x05,
PCMD_GAME_VERSION = 0x06,
} ProgfileCommand;
typedef struct StageProgress {

View file

@ -11,10 +11,10 @@
int taisei_version_compare(TaiseiVersion *v1, TaiseiVersion *v2, TaiseiVersionCmpLevel level) {
int result = 0;
if((result = v1->major - v2->major) && level >= VCMP_MAJOR) return result;
if((result = v1->minor - v2->minor) && level >= VCMP_MINOR) return result;
if((result = v1->patch - v2->patch) && level >= VCMP_PATCH) return result;
if((result = v1->tweak - v2->tweak) && level >= VCMP_TWEAK) return result;
if((result = (int)v1->major - (int)v2->major) && level >= VCMP_MAJOR) return result;
if((result = (int)v1->minor - (int)v2->minor) && level >= VCMP_MINOR) return result;
if((result = (int)v1->patch - (int)v2->patch) && level >= VCMP_PATCH) return result;
if((result = (int)v1->tweak - (int)v2->tweak) && level >= VCMP_TWEAK) return result;
return result;
}

View file

@ -54,5 +54,3 @@ int taisei_version_compare(TaiseiVersion *v1, TaiseiVersion *v2, TaiseiVersionCm
char* taisei_version_tostring(TaiseiVersion *version);
size_t taisei_version_read(SDL_RWops *rwops, TaiseiVersion *version);
size_t taisei_version_write(SDL_RWops *rwops, TaiseiVersion *version);