Encode library version and game version into savegame files and check them both

This commit is contained in:
2026-05-08 23:48:35 -04:00
parent ff6b282112
commit 4c771227f5
3 changed files with 41 additions and 16 deletions

View File

@@ -1,7 +1,7 @@
#ifndef _SDL_GAMECONTROLLERDB_H_ #ifndef _SDL_GAMECONTROLLERDB_H_
#define _SDL_GAMECONTROLLERDB_H_ #define _SDL_GAMECONTROLLERDB_H_
// Taken from https://raw.githubusercontent.com/mdqinc/SDL_GameControllerDB/refs/heads/master/gamecontrollerdb.txt on Fri May 8 11:02:47 PM EDT 2026 // Taken from https://raw.githubusercontent.com/mdqinc/SDL_GameControllerDB/refs/heads/master/gamecontrollerdb.txt on Fri May 8 11:47:47 PM EDT 2026
#define AKGL_SDL_GAMECONTROLLER_DB_LEN 2227 #define AKGL_SDL_GAMECONTROLLER_DB_LEN 2227

View File

@@ -6,6 +6,8 @@
#include <SDL3_mixer/SDL_mixer.h> #include <SDL3_mixer/SDL_mixer.h>
#include "tilemap.h" #include "tilemap.h"
#define AKGL_VERSION "0.1.0"
#define AKGL_GAME_AUDIO_TRACK_BGM 1 #define AKGL_GAME_AUDIO_TRACK_BGM 1
#define AKGL_GAME_AUDIO_MAX_TRACKS 64 #define AKGL_GAME_AUDIO_MAX_TRACKS 64
@@ -25,6 +27,7 @@ typedef struct {
} akgl_GameState; } akgl_GameState;
typedef struct { typedef struct {
char libversion[32];
char version[32]; char version[32];
char name[256]; char name[256];
char uri[256]; char uri[256];

View File

@@ -34,6 +34,7 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_game_init()
int i = 0; int i = 0;
PREPARE_ERROR(errctx); PREPARE_ERROR(errctx);
ATTEMPT { ATTEMPT {
strncpy((char *)&game.libversion, AKGL_VERSION, 32);
game.gameStartTime = SDL_GetTicksNS(); game.gameStartTime = SDL_GetTicksNS();
game.lastIterTime = game.gameStartTime; game.lastIterTime = game.gameStartTime;
game.lastFPSTime = game.gameStartTime; game.lastFPSTime = game.gameStartTime;
@@ -135,24 +136,23 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_game_save(char *fpath)
SUCCEED_RETURN(errctx); // SUCCEED_NORETURN if in main(). SUCCEED_RETURN(errctx); // SUCCEED_NORETURN if in main().
} }
akerr_ErrorContext AKERR_NOIGNORE *akgl_game_load(char *fpath) akerr_ErrorContext AKERR_NOIGNORE *akgl_game_load_versioncmp(FILE *fp, const char *versiontype, char *curversion)
{ {
FILE *fp = NULL;
char versionstr[32]; char versionstr[32];
semver_t current_version = {}; semver_t current_version = {};
semver_t compare_version = {}; semver_t compare_version = {};
PREPARE_ERROR(errctx); PREPARE_ERROR(errctx);
FAIL_ZERO_RETURN(errctx, fpath, AKERR_NULLPOINTER, "NULL file path"); FAIL_ZERO_RETURN(errctx, fp, AKERR_NULLPOINTER, "NULL file pointer");
ATTEMPT { ATTEMPT {
// Check save game library version
FAIL_NONZERO_BREAK( FAIL_NONZERO_BREAK(
errctx, errctx,
semver_parse((const char *)&game.version, &current_version), semver_parse((const char *)curversion, &current_version),
AKERR_VALUE, AKERR_VALUE,
"Invalid semantic version in current game: %s", "Invalid semantic %s version in current game: %s",
(char *)&current_version); versiontype,
fp = fopen(fpath, "rb"); (char *)curversion);
FAIL_NONZERO_BREAK( FAIL_NONZERO_BREAK(
errctx, errctx,
(fread((void *)&versionstr, 1, 32, fp) < 32), (fread((void *)&versionstr, 1, 32, fp) < 32),
@@ -162,13 +162,37 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_game_load(char *fpath)
errctx, errctx,
semver_parse((const char *)&versionstr, &compare_version), semver_parse((const char *)&versionstr, &compare_version),
AKERR_VALUE, AKERR_VALUE,
"Invalid semantic version in save game: %s", "Invalid semantic %s version in save game: %s",
versiontype,
(char *)&versionstr); (char *)&versionstr);
FAIL_ZERO_BREAK( FAIL_ZERO_BREAK(
errctx, errctx,
semver_satisfies(compare_version, current_version, "^"), semver_satisfies(compare_version, current_version, "="),
AKERR_API, AKERR_API,
"Incompatible save game version"); "Incompatible save game %s version (%s ^ %s)",
versiontype,
curversion,
(char *)&versionstr);
} CLEANUP {
semver_free(&current_version);
semver_free(&compare_version);
} PROCESS(errctx) {
} FINISH(errctx, true);
SUCCEED_RETURN(errctx);
}
akerr_ErrorContext AKERR_NOIGNORE *akgl_game_load(char *fpath)
{
FILE *fp = NULL;
PREPARE_ERROR(errctx);
FAIL_ZERO_RETURN(errctx, fpath, AKERR_NULLPOINTER, "NULL file path");
ATTEMPT {
fp = fopen(fpath, "rb");
FAIL_ZERO_BREAK(errctx, fp, errno, "%s", fpath);
CATCH(errctx, akgl_game_load_versioncmp(fp, "library", (char *)AKGL_VERSION));
CATCH(errctx, akgl_game_load_versioncmp(fp, "game", (char *)&game.version));
rewind(fp); rewind(fp);
FAIL_NONZERO_BREAK( FAIL_NONZERO_BREAK(
errctx, errctx,
@@ -179,8 +203,6 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_game_load(char *fpath)
if ( fp != NULL ) { if ( fp != NULL ) {
fclose(fp); fclose(fp);
} }
semver_free(&current_version);
semver_free(&compare_version);
} PROCESS(errctx) { } PROCESS(errctx) {
} FINISH(errctx, true); } FINISH(errctx, true);