From 1a34dac8bac68d95e0af5d4f8c96b2804030f74f Mon Sep 17 00:00:00 2001 From: JuanJakobo Date: Mon, 24 Oct 2022 18:20:03 +0200 Subject: [PATCH] Snake Plugin: Implement #1041, save game state on pause --- .../plugins/snake_game/application.fam | 8 +- .../snake_game/helpers/snake_file_handler.c | 143 ++++++++++++++++++ .../snake_game/helpers/snake_file_handler.h | 20 +++ applications/plugins/snake_game/snake_game.c | 6 +- 4 files changed, 174 insertions(+), 3 deletions(-) create mode 100644 applications/plugins/snake_game/helpers/snake_file_handler.c create mode 100644 applications/plugins/snake_game/helpers/snake_file_handler.h diff --git a/applications/plugins/snake_game/application.fam b/applications/plugins/snake_game/application.fam index d55f53bb1..d0378ac11 100644 --- a/applications/plugins/snake_game/application.fam +++ b/applications/plugins/snake_game/application.fam @@ -4,8 +4,12 @@ App( apptype=FlipperAppType.PLUGIN, entry_point="snake_game_app", cdefines=["APP_SNAKE_GAME"], - requires=["gui"], - stack_size=1 * 1024, + requires=[ + "gui", + "notification", + "storage", + ], + stack_size=2 * 1024, order=30, fap_icon="snake_10px.png", fap_category="Games", diff --git a/applications/plugins/snake_game/helpers/snake_file_handler.c b/applications/plugins/snake_game/helpers/snake_file_handler.c new file mode 100644 index 000000000..415c840de --- /dev/null +++ b/applications/plugins/snake_game/helpers/snake_file_handler.c @@ -0,0 +1,143 @@ +#include "snake_file_handler.h" + +#include +#include + +static void snake_game_close_file(FlipperFormat* file) { + if(file == NULL){ + furi_record_close(RECORD_STORAGE); + return; + } + flipper_format_file_close(file); + flipper_format_free(file); + furi_record_close(RECORD_STORAGE); +} + +static FlipperFormat* snake_game_open_file(Storage* storage) { + FlipperFormat* file = flipper_format_file_alloc(storage); + + if(storage_common_stat(storage, SNAKE_GAME_FILE_PATH, NULL) == FSE_OK) { + if(!flipper_format_file_open_existing(file, SNAKE_GAME_FILE_PATH)) { + snake_game_close_file(file); + return NULL; + } + } else { + if(!flipper_format_file_open_new(file, SNAKE_GAME_FILE_PATH)) { + snake_game_close_file(file); + return NULL; + } + + flipper_format_write_header_cstr(file, SNAKE_GAME_FILE_HEADER, SNAKE_GAME_FILE_ACTUAL_VERSION); + flipper_format_rewind(file); + } + return file; +} + +void snake_game_save_game_to_file(SnakeState* const snake_state) { + Storage* storage = furi_record_open(RECORD_STORAGE); + FlipperFormat* file = snake_game_open_file(storage); + + uint32_t temp = snake_state->len; + if(!flipper_format_insert_or_update_uint32(file, SNAKE_GAME_CONFIG_KEY_LEN,&temp, 1)){ + snake_game_close_file(file); + return; + } + + uint16_t array_size = snake_state->len * 2; + uint32_t temp_array[array_size]; + for(int16_t i = 0, a = 0; a < array_size && i < snake_state->len; i++){ + temp_array[a++] = snake_state->points[i].x; + temp_array[a++] = snake_state->points[i].y; + } + if(!flipper_format_insert_or_update_uint32(file, SNAKE_GAME_CONFIG_KEY_POINTS, temp_array, array_size)){ + snake_game_close_file(file); + return; + } + + temp = snake_state->currentMovement; + if(!flipper_format_insert_or_update_uint32(file, SNAKE_GAME_CONFIG_KEY_CURRENT_MOVEMENT,&temp, 1)){ + snake_game_close_file(file); + return; + } + + temp = snake_state->nextMovement; + if(!flipper_format_insert_or_update_uint32(file, SNAKE_GAME_CONFIG_KEY_NEXT_MOVEMENT,&temp, 1)){ + snake_game_close_file(file); + return; + } + + array_size = 2; + uint32_t temp_point_array[array_size]; + temp_point_array[0] = snake_state->fruit.x; + temp_point_array[1] = snake_state->fruit.y; + if(!flipper_format_insert_or_update_uint32(file, SNAKE_GAME_CONFIG_KEY_FRUIT_POINTS, temp_point_array, array_size)){ + snake_game_close_file(file); + return; + } + + snake_game_close_file(file); +} + +bool snake_game_init_game_from_file(SnakeState* const snake_state) { + Storage* storage = furi_record_open(RECORD_STORAGE); + FlipperFormat* file = snake_game_open_file(storage); + + FuriString* file_type = furi_string_alloc(); + uint32_t version = 1; + if(!flipper_format_read_header(file, file_type, &version)) { + furi_string_free(file_type); + snake_game_close_file(file); + return false; + } + furi_string_free(file_type); + + uint32_t temp; + if(!flipper_format_read_uint32(file, SNAKE_GAME_CONFIG_KEY_LEN, &temp, 1)){ + snake_game_close_file(file); + return false; + } + snake_state->len = temp; + flipper_format_delete_key(file, SNAKE_GAME_CONFIG_KEY_LEN); + + uint16_t array_size = snake_state->len * 2; + uint32_t temp_array[array_size]; + if(!flipper_format_read_uint32(file, SNAKE_GAME_CONFIG_KEY_POINTS, temp_array, array_size)){ + snake_game_close_file(file); + return false; + } + + for(int16_t i = 0, a = 0; a < array_size && i < snake_state->len; i++){ + snake_state->points[i].x = temp_array[a++]; + snake_state->points[i].y = temp_array[a++]; + } + flipper_format_delete_key(file, SNAKE_GAME_CONFIG_KEY_POINTS); + + if(!flipper_format_read_uint32(file, SNAKE_GAME_CONFIG_KEY_CURRENT_MOVEMENT, &temp, 1)){ + snake_game_close_file(file); + return false; + } + snake_state->currentMovement = temp; + flipper_format_delete_key(file, SNAKE_GAME_CONFIG_KEY_CURRENT_MOVEMENT); + + if(!flipper_format_read_uint32(file, SNAKE_GAME_CONFIG_KEY_NEXT_MOVEMENT, &temp, 1)){ + snake_game_close_file(file); + return false; + } + snake_state->nextMovement = temp; + flipper_format_delete_key(file, SNAKE_GAME_CONFIG_KEY_NEXT_MOVEMENT); + + + array_size = 2; + uint32_t temp_point_array[array_size]; + if(!flipper_format_read_uint32(file, SNAKE_GAME_CONFIG_KEY_FRUIT_POINTS, temp_point_array, array_size)){ + snake_game_close_file(file); + return false; + } + snake_state->fruit.x = temp_point_array[0]; + snake_state->fruit.y = temp_point_array[1]; + flipper_format_delete_key(file, SNAKE_GAME_CONFIG_KEY_FRUIT_POINTS); + + snake_game_close_file(file); + + return true; +} diff --git a/applications/plugins/snake_game/helpers/snake_file_handler.h b/applications/plugins/snake_game/helpers/snake_file_handler.h new file mode 100644 index 000000000..3a89114c3 --- /dev/null +++ b/applications/plugins/snake_game/helpers/snake_file_handler.h @@ -0,0 +1,20 @@ +#pragma once + +#include "snake_types.h" +#include +#include + +#define SNAKE_GAME_FILE_PATH "/ext/apps/games/snake.stat" + +#define SNAKE_GAME_FILE_HEADER "Flipper Snake plugin run file" +#define SNAKE_GAME_FILE_ACTUAL_VERSION 1 + +#define SNAKE_GAME_CONFIG_KEY_POINTS "SnakePoints" +#define SNAKE_GAME_CONFIG_KEY_LEN "SnakeLen" +#define SNAKE_GAME_CONFIG_KEY_CURRENT_MOVEMENT "CurrentMovement" +#define SNAKE_GAME_CONFIG_KEY_NEXT_MOVEMENT "NextMovement" +#define SNAKE_GAME_CONFIG_KEY_FRUIT_POINTS "FruitPoints" + +void snake_game_save_game_to_file(SnakeState* const snake_state); + +bool snake_game_init_game_from_file(SnakeState* const snake_state); diff --git a/applications/plugins/snake_game/snake_game.c b/applications/plugins/snake_game/snake_game.c index fdd87b504..0b6cd85f3 100644 --- a/applications/plugins/snake_game/snake_game.c +++ b/applications/plugins/snake_game/snake_game.c @@ -1,3 +1,4 @@ +#include "helpers/snake_file_handler.h" #include "helpers/snake_types.h" #include @@ -279,7 +280,8 @@ int32_t snake_game_app(void* p) { FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(SnakeEvent)); SnakeState* snake_state = malloc(sizeof(SnakeState)); - snake_game_init_game(snake_state); + if(!snake_game_init_game_from_file(snake_state)) + snake_game_init_game(snake_state); ValueMutex state_mutex; if(!init_mutex(&state_mutex, snake_state, sizeof(SnakeState))) { @@ -334,6 +336,8 @@ int32_t snake_game_app(void* p) { } break; case InputKeyBack: + if(snake_state->state == GameStateLife) + snake_game_save_game_to_file(snake_state); processing = false; break; }