From f67f9e26e2a904a1672098a5e584df4611bb2a01 Mon Sep 17 00:00:00 2001 From: En Yi Date: Wed, 3 Sep 2025 23:11:19 +0800 Subject: [PATCH] Persist settings --- .gitignore | 1 + engine/engine.c | 73 ++++++++++++++++++++++++++++++++++++++++++ engine/engine.h | 5 +++ main.c | 1 + scenes/options_scene.c | 2 ++ 5 files changed, 82 insertions(+) diff --git a/.gitignore b/.gitignore index 26110c9..3ad0f00 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ compile_commands.json .gdb_history heaptrack.* save.dat +settings.dat diff --git a/engine/engine.c b/engine/engine.c index 678415c..a310c76 100644 --- a/engine/engine.c +++ b/engine/engine.c @@ -3,6 +3,8 @@ #include +#define SETTINGS_FILE "settings.dat" + void init_engine(GameEngine_t* engine, Vector2 starting_win_size) { InitAudioDevice(); @@ -48,6 +50,77 @@ int get_keybind_or_default(GameEngine_t* engine, ActionType_t action, int defaul return key; } +#define PAIR_SIZE(a,b) (sizeof(a) + sizeof(b)) +int load_keybinds(GameEngine_t* engine) +{ + int len = 0; + + float volume = 1.0f; + unsigned char* data = LoadFileData(SETTINGS_FILE, &len); + + if (data != NULL) + { + if (len >= 4) + { + memcpy(&volume, data, sizeof(volume)); + SetMasterVolume(volume); + len -= 4; + } + + len /= 2; // 2 bytes for each key and actions + len /= 2; // key-action pair + + unsigned char* keybind_data = data + sizeof(volume); + for (int i = 0; i < len; ++i) + { + uint16_t key = 0; + uint16_t action = 0; + memcpy(&key, keybind_data + i * PAIR_SIZE(key, action), sizeof(key)); + memcpy(&action, keybind_data + i * PAIR_SIZE(key, action)+ sizeof(key), sizeof(action)); + sc_map_get_64(&engine->keybinds, key); + if (sc_map_found(&engine->keybinds)) + { + sc_map_put_64(&engine->keybinds, key, (ActionType_t)(action)); + } + } + UnloadFileData(data); + } + else + { + // Create the file if not found + writeout_keybinds(engine); + } + return 0; +} + +int writeout_keybinds(GameEngine_t* engine) +{ + uint16_t key = 0; + uint16_t action = 0; + float volume = GetMasterVolume(); + unsigned int n_keys = sc_map_size_64(&engine->keybinds); + uint32_t n_bytes = sizeof(volume) + PAIR_SIZE(key, action) * n_keys; + + uint8_t* buf = RL_MALLOC(n_bytes); + if (buf == NULL) + { + return 1; + } + memcpy(buf, &volume, sizeof(volume)); + int i = 0; + uint8_t* keybind_buf = buf + sizeof(volume); + + sc_map_foreach(&engine->keybinds, key, action) + { + memcpy(keybind_buf + i * PAIR_SIZE(key, action), &key, sizeof(key)); + memcpy(keybind_buf + i * PAIR_SIZE(key, action) + sizeof(key), &action, sizeof(action)); + i++; + } + return SaveFileData(SETTINGS_FILE, buf, n_bytes)? 0 : 1; + RL_FREE(buf); + return 0; +} + void remap_scene_keys(GameEngine_t* engine) { // Assume all scene to be init'd diff --git a/engine/engine.h b/engine/engine.h index 293afb5..7c12e2f 100644 --- a/engine/engine.h +++ b/engine/engine.h @@ -98,6 +98,11 @@ void process_inputs(GameEngine_t* engine, Scene_t* scene); void register_keybind(GameEngine_t* engine, int key, ActionType_t action); int get_keybind_or_default(GameEngine_t* engine, ActionType_t action, int default_key); +// You need to register the keybind first before loading them +// Otherwise, they will get ignored +int load_keybinds(GameEngine_t* engine); +int writeout_keybinds(GameEngine_t* engine); + // If a key bind gets changed, this must be called to update the // key -> action mapping for all scene void remap_scene_keys(GameEngine_t* engine); diff --git a/main.c b/main.c index c2f5ee8..dbd1ea6 100644 --- a/main.c +++ b/main.c @@ -47,6 +47,7 @@ int main(void) register_keybind(&engine, KEY_Q, ACTION_EXIT); register_keybind(&engine, KEY_Z, ACTION_LOOKAHEAD); register_keybind(&engine, KEY_R, ACTION_RESTART); + load_keybinds(&engine); load_sfx(&engine, "snd_jump", PLAYER_JMP_SFX); load_sfx(&engine, "snd_land", PLAYER_LAND_SFX); diff --git a/scenes/options_scene.c b/scenes/options_scene.c index aeb3a32..85254ac 100644 --- a/scenes/options_scene.c +++ b/scenes/options_scene.c @@ -243,6 +243,8 @@ static void exec_component_function(Scene_t* scene, uint16_t sel) scene->reset_function(scene); data->curr_selection = sel + n_binds + 1; data->old_volume_value = data->volume_value; + + writeout_keybinds(scene->engine); } else {