Added basic game save function, doesn't save much yet, but implements version comparison of binary saves for compatibility
This commit is contained in:
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "deps/semver"]
|
||||||
|
path = deps/semver
|
||||||
|
url = git@github.com:h2non/semver.c.git
|
||||||
@@ -35,6 +35,7 @@ add_custom_command(
|
|||||||
# Add include directories
|
# Add include directories
|
||||||
include_directories(${SDL3_INCLUDE_DIRS})
|
include_directories(${SDL3_INCLUDE_DIRS})
|
||||||
add_library(akgl SHARED
|
add_library(akgl SHARED
|
||||||
|
deps/semver/semver.c
|
||||||
src/actor.c
|
src/actor.c
|
||||||
src/actor_state_string_names.c
|
src/actor_state_string_names.c
|
||||||
src/text.c
|
src/text.c
|
||||||
@@ -55,7 +56,6 @@ add_library(akgl SHARED
|
|||||||
|
|
||||||
|
|
||||||
add_executable(charviewer util/charviewer.c)
|
add_executable(charviewer util/charviewer.c)
|
||||||
|
|
||||||
add_executable(test_actor tests/actor.c)
|
add_executable(test_actor tests/actor.c)
|
||||||
add_executable(test_bitmasks tests/bitmasks.c)
|
add_executable(test_bitmasks tests/bitmasks.c)
|
||||||
add_executable(test_character tests/character.c)
|
add_executable(test_character tests/character.c)
|
||||||
@@ -64,6 +64,7 @@ add_executable(test_sprite tests/sprite.c)
|
|||||||
add_executable(test_staticstring tests/staticstring.c)
|
add_executable(test_staticstring tests/staticstring.c)
|
||||||
add_executable(test_tilemap tests/tilemap.c)
|
add_executable(test_tilemap tests/tilemap.c)
|
||||||
add_executable(test_util tests/util.c)
|
add_executable(test_util tests/util.c)
|
||||||
|
add_executable(test_semver_unit deps/semver/semver_unit.c)
|
||||||
add_test(NAME actor COMMAND test_actor)
|
add_test(NAME actor COMMAND test_actor)
|
||||||
add_test(NAME bitmasks COMMAND test_bitmasks)
|
add_test(NAME bitmasks COMMAND test_bitmasks)
|
||||||
add_test(NAME character COMMAND test_character)
|
add_test(NAME character COMMAND test_character)
|
||||||
@@ -72,10 +73,12 @@ add_test(NAME sprite COMMAND test_sprite)
|
|||||||
add_test(NAME staticstring COMMAND test_staticstring)
|
add_test(NAME staticstring COMMAND test_staticstring)
|
||||||
add_test(NAME tilemap COMMAND test_tilemap)
|
add_test(NAME tilemap COMMAND test_tilemap)
|
||||||
add_test(NAME util COMMAND test_util)
|
add_test(NAME util COMMAND test_util)
|
||||||
|
add_test(NAME semver_unit COMMAND test_semver_unit)
|
||||||
|
|
||||||
# Specify include directories for the library's headers (if applicable)
|
# Specify include directories for the library's headers (if applicable)
|
||||||
target_include_directories(akgl PUBLIC
|
target_include_directories(akgl PUBLIC
|
||||||
include/
|
include/
|
||||||
|
deps/semver/
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(akgl
|
target_link_libraries(akgl
|
||||||
@@ -100,6 +103,7 @@ target_link_libraries(charviewer PRIVATE akerror::akerror akgl SDL3::SDL3 SDL3_t
|
|||||||
set(main_lib_dest "lib/akgl-${MY_LIBRARY_VERSION}")
|
set(main_lib_dest "lib/akgl-${MY_LIBRARY_VERSION}")
|
||||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/akgl.pc DESTINATION "lib/pkgconfig/")
|
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/akgl.pc DESTINATION "lib/pkgconfig/")
|
||||||
install(TARGETS akgl DESTINATION "lib/")
|
install(TARGETS akgl DESTINATION "lib/")
|
||||||
|
install(FILES "deps/semver/semver.h" DESTINATION "include/")
|
||||||
install(FILES "include/akgl/actor.h" DESTINATION "include/akgl/")
|
install(FILES "include/akgl/actor.h" DESTINATION "include/akgl/")
|
||||||
install(FILES "include/akgl/types.h" DESTINATION "include/akgl/")
|
install(FILES "include/akgl/types.h" DESTINATION "include/akgl/")
|
||||||
install(FILES "include/akgl/text.h" DESTINATION "include/akgl/")
|
install(FILES "include/akgl/text.h" DESTINATION "include/akgl/")
|
||||||
|
|||||||
1
deps/semver
vendored
Submodule
1
deps/semver
vendored
Submodule
Submodule deps/semver added at bd1db234a6
@@ -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 10:15:45 PM EDT 2026
|
// Taken from https://raw.githubusercontent.com/mdqinc/SDL_GameControllerDB/refs/heads/master/gamecontrollerdb.txt on Fri May 8 11:02:47 PM EDT 2026
|
||||||
|
|
||||||
#define AKGL_SDL_GAMECONTROLLER_DB_LEN 2227
|
#define AKGL_SDL_GAMECONTROLLER_DB_LEN 2227
|
||||||
|
|
||||||
|
|||||||
68
src/game.c
68
src/game.c
@@ -4,6 +4,7 @@
|
|||||||
#include <SDL3_ttf/SDL_ttf.h>
|
#include <SDL3_ttf/SDL_ttf.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <akerror.h>
|
#include <akerror.h>
|
||||||
|
#include <semver.h>
|
||||||
|
|
||||||
#include <akgl/game.h>
|
#include <akgl/game.h>
|
||||||
#include <akgl/controller.h>
|
#include <akgl/controller.h>
|
||||||
@@ -127,34 +128,61 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_game_save(char *fpath)
|
|||||||
PREPARE_ERROR(errctx);
|
PREPARE_ERROR(errctx);
|
||||||
|
|
||||||
FAIL_ZERO_RETURN(errctx, fpath, AKERR_NULLPOINTER, "NULL file path");
|
FAIL_ZERO_RETURN(errctx, fpath, AKERR_NULLPOINTER, "NULL file path");
|
||||||
fp = fopen(fpath, "rb");
|
fp = fopen(fpath, "wb");
|
||||||
|
FAIL_ZERO_RETURN(errctx, fp, errno, "%s", fpath);
|
||||||
|
fwrite(&game, 1, sizeof(akgl_Game), fp);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
SUCCEED(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(char *fpath)
|
||||||
{
|
{
|
||||||
FILE *fp = NULL;
|
FILE *fp = NULL;
|
||||||
char version[32];
|
char versionstr[32];
|
||||||
|
semver_t current_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, fpath, AKERR_NULLPOINTER, "NULL file path");
|
||||||
fp = fopen(fpath, "rb");
|
|
||||||
FAIL_ZERO_RETURN(
|
ATTEMPT {
|
||||||
errctx,
|
FAIL_NONZERO_BREAK(
|
||||||
(fread((void *)&version, 1, 32, fp) < 32),
|
errctx,
|
||||||
AKERR_IO,
|
semver_parse((const char *)&game.version, ¤t_version),
|
||||||
|
AKERR_VALUE,
|
||||||
|
"Invalid semantic version in current game: %s",
|
||||||
|
(char *)¤t_version);
|
||||||
|
fp = fopen(fpath, "rb");
|
||||||
|
FAIL_NONZERO_BREAK(
|
||||||
|
errctx,
|
||||||
|
(fread((void *)&versionstr, 1, 32, fp) < 32),
|
||||||
|
AKERR_IO,
|
||||||
|
"Corrupt save file");
|
||||||
|
FAIL_NONZERO_BREAK(
|
||||||
|
errctx,
|
||||||
|
semver_parse((const char *)&versionstr, &compare_version),
|
||||||
|
AKERR_VALUE,
|
||||||
|
"Invalid semantic version in save game: %s",
|
||||||
|
(char *)&versionstr);
|
||||||
|
FAIL_ZERO_BREAK(
|
||||||
|
errctx,
|
||||||
|
semver_satisfies(compare_version, current_version, "^"),
|
||||||
|
AKERR_API,
|
||||||
|
"Incompatible save game version");
|
||||||
|
rewind(fp);
|
||||||
|
FAIL_NONZERO_BREAK(
|
||||||
|
errctx,
|
||||||
|
(fread((void *)&game, 1, sizeof(akgl_Game), fp) < sizeof(akgl_Game)),
|
||||||
|
AKERR_IO,
|
||||||
"Corrupt save file");
|
"Corrupt save file");
|
||||||
FAIL_ZERO_RETURN(
|
} CLEANUP {
|
||||||
errctx,
|
if ( fp != NULL ) {
|
||||||
strncmp((char *)&game.version, (char *)&version, 32),
|
fclose(fp);
|
||||||
AKERR_API,
|
}
|
||||||
"Save game can not be loaded, it is from an incompatible version");
|
semver_free(¤t_version);
|
||||||
rewind(fp);
|
semver_free(&compare_version);
|
||||||
FAIL_ZERO_RETURN(
|
} PROCESS(errctx) {
|
||||||
errctx,
|
} FINISH(errctx, true);
|
||||||
(fread((void *)&game, 1, sizeof(akgl_Game), fp) < sizeof(akgl_Game)),
|
|
||||||
AKERR_IO,
|
SUCCEED_RETURN(errctx);
|
||||||
"Corrupt save file");
|
|
||||||
SUCCEED(errctx);
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user