Encode library version and game version into savegame files and check them both
This commit is contained in:
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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];
|
||||||
|
|||||||
48
src/game.c
48
src/game.c
@@ -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, ¤t_version),
|
semver_parse((const char *)curversion, ¤t_version),
|
||||||
AKERR_VALUE,
|
AKERR_VALUE,
|
||||||
"Invalid semantic version in current game: %s",
|
"Invalid semantic %s version in current game: %s",
|
||||||
(char *)¤t_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(¤t_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(¤t_version);
|
|
||||||
semver_free(&compare_version);
|
|
||||||
} PROCESS(errctx) {
|
} PROCESS(errctx) {
|
||||||
} FINISH(errctx, true);
|
} FINISH(errctx, true);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user