jblanked 1 год назад
Родитель
Сommit
305e9050e8
9 измененных файлов с 337 добавлено и 108 удалено
  1. 24 4
      callback/callback.c
  2. 85 1
      flip_storage/storage.c
  3. 5 1
      flip_storage/storage.h
  4. 3 12
      game/game.c
  5. 120 0
      game/icon.c
  6. 2 1
      game/icon.h
  7. 53 58
      game/level.c
  8. 2 3
      game/level.h
  9. 43 28
      game/world.c

+ 24 - 4
callback/callback.c

@@ -780,26 +780,46 @@ static char *flip_world_parse_worlds(DataLoaderModel *model)
         FURI_LOG_E(TAG, "Failed to load world data");
         return "Failed to load world data";
     }
+    // first save list of names
+    FuriString *names = get_json_value_furi("names", world_data);
+    if (!names)
+    {
+        FURI_LOG_E(TAG, "Failed to get names");
+        furi_string_free(world_data);
+        return "Failed to get names";
+    }
+    if (!save_world_names(names))
+    {
+        FURI_LOG_E(TAG, "Failed to save world names");
+        furi_string_free(names);
+        furi_string_free(world_data);
+        return "Failed to save world names";
+    }
+    furi_string_free(names);
     // we used 10 since we passed 10 in the request
     for (int i = 0; i < 10; i++)
     {
-        char *json = get_json_array_value("worlds", i, furi_string_get_cstr(world_data));
-        if (!json)
+        FuriString *worlds = get_json_array_value_furi("worlds", i, world_data);
+        if (!worlds)
         {
             FURI_LOG_E(TAG, "Failed to get worlds. Data likely empty");
             break;
         }
-        char *world_name = get_json_value("name", json);
+        FuriString *world_name = get_json_array_value_furi("names", i, world_data);
         if (!world_name)
         {
             FURI_LOG_E(TAG, "Failed to get world name");
+            furi_string_free(worlds);
             break;
         }
-        if (!save_world(world_name, json))
+        if (!save_world_furi(world_name, worlds))
         {
             FURI_LOG_E(TAG, "Failed to save world");
         }
+        furi_string_free(world_name);
+        furi_string_free(worlds);
     }
+    furi_string_free(world_data);
     return "World Pack Installed";
 }
 static void flip_world_switch_to_view_get_worlds(FlipWorldApp *app)

+ 85 - 1
flip_storage/storage.c

@@ -229,6 +229,48 @@ bool save_world(
     return true;
 }
 
+bool save_world_furi(FuriString *name, FuriString *world_data)
+{
+    // Create the directory for saving settings
+    char directory_path[256];
+    snprintf(directory_path, sizeof(directory_path), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_world/worlds");
+
+    // Create the directory
+    Storage *storage = furi_record_open(RECORD_STORAGE);
+    storage_common_mkdir(storage, directory_path);
+
+    // Open the settings file
+    File *file = storage_file_alloc(storage);
+    char file_path[256];
+    snprintf(file_path, sizeof(file_path), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_world/worlds/%s.json", furi_string_get_cstr(name));
+
+    // Open the file in write mode
+    if (!storage_file_open(file, file_path, FSAM_WRITE, FSOM_CREATE_ALWAYS))
+    {
+        FURI_LOG_E(HTTP_TAG, "Failed to open file for writing: %s", file_path);
+        storage_file_free(file);
+        furi_record_close(RECORD_STORAGE);
+        return false;
+    }
+
+    // Write the data to the file
+    size_t data_size = furi_string_size(world_data) + 1; // Include null terminator
+    if (storage_file_write(file, furi_string_get_cstr(world_data), data_size) != data_size)
+    {
+        FURI_LOG_E(HTTP_TAG, "Failed to append data to file");
+        storage_file_close(file);
+        storage_file_free(file);
+        furi_record_close(RECORD_STORAGE);
+        return false;
+    }
+
+    storage_file_close(file);
+    storage_file_free(file);
+    furi_record_close(RECORD_STORAGE);
+
+    return true;
+}
+
 bool load_world(
     const char *name,
     char *json_data,
@@ -274,7 +316,7 @@ FuriString *load_furi_world(
 {
     Storage *storage = furi_record_open(RECORD_STORAGE);
     File *file = storage_file_alloc(storage);
-    char file_path[256];
+    char file_path[128];
     snprintf(file_path, sizeof(file_path), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_world/worlds/%s.json", name);
     // Open the file for reading
     if (!storage_file_open(file, file_path, FSAM_READ, FSOM_OPEN_EXISTING))
@@ -360,3 +402,45 @@ bool world_exists(const char *name)
     furi_record_close(RECORD_STORAGE);
     return does_exist;
 }
+
+bool save_world_names(const FuriString *json)
+{
+    // Create the directory for saving settings
+    char directory_path[256];
+    snprintf(directory_path, sizeof(directory_path), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_world/worlds");
+
+    // Create the directory
+    Storage *storage = furi_record_open(RECORD_STORAGE);
+    storage_common_mkdir(storage, directory_path);
+
+    // Open the settings file
+    File *file = storage_file_alloc(storage);
+    char file_path[128];
+    snprintf(file_path, sizeof(file_path), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_world/worlds/world_list.json");
+
+    // Open the file in write mode
+    if (!storage_file_open(file, file_path, FSAM_WRITE, FSOM_CREATE_ALWAYS))
+    {
+        FURI_LOG_E(HTTP_TAG, "Failed to open file for writing: %s", file_path);
+        storage_file_free(file);
+        furi_record_close(RECORD_STORAGE);
+        return false;
+    }
+
+    // Write the data to the file
+    size_t data_size = furi_string_size(json) + 1; // Include null terminator
+    if (storage_file_write(file, furi_string_get_cstr(json), data_size) != data_size)
+    {
+        FURI_LOG_E(HTTP_TAG, "Failed to append data to file");
+        storage_file_close(file);
+        storage_file_free(file);
+        furi_record_close(RECORD_STORAGE);
+        return false;
+    }
+
+    storage_file_close(file);
+    storage_file_free(file);
+    furi_record_close(RECORD_STORAGE);
+
+    return true;
+}

+ 5 - 1
flip_storage/storage.h

@@ -28,6 +28,8 @@ bool save_world(
     const char *name,
     const char *world_data);
 
+bool save_world_furi(FuriString *name, FuriString *world_data);
+
 bool load_world(
     const char *name,
     char *json_data,
@@ -37,4 +39,6 @@ FuriString *load_furi_world(
     const char *name);
 
 bool world_exists(
-    const char *name);
+    const char *name);
+
+bool save_world_names(const FuriString *json);

+ 3 - 12
game/game.c

@@ -68,7 +68,7 @@ static void player_update(Entity *self, GameManager *manager, void *context)
     if (input.held & GameKeyOk)
     {
         game_manager_next_level_set(manager, game_manager_current_level_get(manager) == level_tree ? level_example : level_tree);
-        furi_delay_ms(1000);
+        furi_delay_ms(500);
         return;
     }
 
@@ -138,21 +138,12 @@ static void game_start(GameManager *game_manager, void *ctx)
     game_context->score = 0;
 
     // load all levels
-    // if (level_load_all())
-    // {
-    //     // loop through all levels and add them to the game
-    //     for (int i = level_count; i > 0; i--)
-    //     {
-    //         levels[i] = game_manager_add_level(game_manager, level_behaviors[i]);
-    //     }
-    // }
-    // else
+    // if (!level_load_all(game_manager))
     // {
     //     FURI_LOG_E("Game", "Failed to load levels");
     //     easy_flipper_dialog("[LEVEL ERROR]", "No level data installed.\n\n\nSettings -> Game ->\nInstall Official Level Pack");
-    //     game_manager_add_level(game_manager, &example_level);
+    //     game_manager_add_level(game_manager, &tree_level);
     // }
-
     level_tree = game_manager_add_level(game_manager, &tree_level);
     level_example = game_manager_add_level(game_manager, &example_level);
 }

+ 120 - 0
game/icon.c

@@ -175,4 +175,124 @@ const Icon *get_icon(char *name)
 
     // If no match is found
     return NULL;
+}
+const Icon *get_icon_furi(FuriString *name)
+{
+    if (furi_string_cmp(name, "earth") == 0)
+    {
+        return &I_icon_earth_15x16;
+    }
+    if (furi_string_cmp(name, "home") == 0)
+    {
+        return &I_icon_home_15x16;
+    }
+    if (furi_string_cmp(name, "house") == 0)
+    {
+        return &I_icon_house_48x48px;
+    }
+    if (furi_string_cmp(name, "house_3d") == 0)
+    {
+        return &I_icon_house_3d_34x45px;
+    }
+    if (furi_string_cmp(name, "info") == 0)
+    {
+        return &I_icon_info_15x16;
+    }
+    if (furi_string_cmp(name, "man") == 0)
+    {
+        return &I_icon_man_7x16;
+    }
+    if (furi_string_cmp(name, "plant") == 0)
+    {
+        return &I_icon_plant_16x16;
+    }
+    if (furi_string_cmp(name, "plant_fern") == 0)
+    {
+        return &I_icon_plant_fern_18x16px;
+    }
+    if (furi_string_cmp(name, "plant_pointy") == 0)
+    {
+        return &I_icon_plant_pointy_13x16px;
+    }
+    if (furi_string_cmp(name, "tree") == 0)
+    {
+        return &I_icon_tree_16x16;
+    }
+    if (furi_string_cmp(name, "tree_29x30") == 0)
+    {
+        return &I_icon_tree_29x30px;
+    }
+    if (furi_string_cmp(name, "tree_48x48") == 0)
+    {
+        return &I_icon_tree_48x48px;
+    }
+    if (furi_string_cmp(name, "woman") == 0)
+    {
+        return &I_icon_woman_9x16;
+    }
+    if (furi_string_cmp(name, "chest_closed") == 0)
+    {
+        return &I_icon_chest_closed_16x13px;
+    }
+    if (furi_string_cmp(name, "chest_open") == 0)
+    {
+        return &I_icon_chest_open_16x16px;
+    }
+    if (furi_string_cmp(name, "fence") == 0)
+    {
+        return &I_icon_fence_16x8px;
+    }
+    if (furi_string_cmp(name, "fence_end") == 0)
+    {
+        return &I_icon_fence_end_16x8px;
+    }
+    if (furi_string_cmp(name, "flower") == 0)
+    {
+        return &I_icon_flower_16x16;
+    }
+    if (furi_string_cmp(name, "lake_bottom") == 0)
+    {
+        return &I_icon_lake_bottom_31x31px;
+    }
+    if (furi_string_cmp(name, "lake_bottom_left") == 0)
+    {
+        return &I_icon_lake_bottom_left_31x31px;
+    }
+    if (furi_string_cmp(name, "lake_bottom_right") == 0)
+    {
+        return &I_icon_lake_bottom_right_31x31px;
+    }
+    if (furi_string_cmp(name, "lake_left") == 0)
+    {
+        return &I_icon_lake_left_31x31;
+    }
+    if (furi_string_cmp(name, "lake_right") == 0)
+    {
+        return &I_icon_lake_right_31x31px;
+    }
+    if (furi_string_cmp(name, "lake_top") == 0)
+    {
+        return &I_icon_lake_top_31x31px;
+    }
+    if (furi_string_cmp(name, "lake_top_left") == 0)
+    {
+        return &I_icon_lake_top_left_31x31px;
+    }
+    if (furi_string_cmp(name, "lake_top_right") == 0)
+    {
+        return &I_icon_lake_top_right_31x31px;
+    }
+    if (furi_string_cmp(name, "rock_large") == 0)
+    {
+        return &I_icon_rock_large_18x19px;
+    }
+    if (furi_string_cmp(name, "rock_medium") == 0)
+    {
+        return &I_icon_rock_medium_16x14px;
+    }
+    if (furi_string_cmp(name, "rock_small") == 0)
+    {
+        return &I_icon_rock_small_10x8px;
+    }
+    return NULL;
 }

+ 2 - 1
game/icon.h

@@ -12,4 +12,5 @@ typedef struct
 } IconContext;
 
 extern const EntityDescription icon_desc;
-const Icon *get_icon(char *name);
+const Icon *get_icon(char *name);
+const Icon *get_icon_furi(FuriString *name);

+ 53 - 58
game/level.c

@@ -7,19 +7,31 @@ static void level_start(Level *level, GameManager *manager, void *context)
     UNUSED(manager);
     LevelContext *level_context = context;
     // check if the world exists
-    if (!world_exists(level_context->id))
-    {
-        FURI_LOG_E("Game", "World does not exist");
-        easy_flipper_dialog("[WORLD ERROR]", "No world data installed.\n\n\nSettings -> Game ->\nInstall Official World Pack");
-        draw_example_world(level);
-        return;
-    }
+    // if (!world_exists(level_context->id))
+    // {
+    //     FURI_LOG_E("Game", "World does not exist");
+    //     easy_flipper_dialog("[WORLD ERROR]", "No world data installed.\n\n\nSettings -> Game ->\nInstall Official World Pack");
+    //     draw_example_world(level);
+    //     return;
+    // }
     // draw the world
-    if (!draw_json_world_furi(level, load_furi_world(level_context->id)))
-    {
-        FURI_LOG_E("Game", "World exists but failed to draw.");
+    // FuriString *world_data = load_furi_world(level_context->id);
+    // if (!world_data)
+    // {
+    //     FURI_LOG_E("Game", "Failed to load world data");
+    //     draw_example_world(level);
+    //     return;
+    // }
+    // if (!draw_json_world_furi(level, load_furi_world(level_context->id)))
+    // {
+    //     FURI_LOG_E("Game", "World exists but failed to draw.");
+    //     draw_example_world(level);
+    // }
+    // furi_string_free(world_data);
+    if (level_context->index == 0)
+        draw_tree_world(level);
+    else
         draw_example_world(level);
-    }
 }
 
 static void level_alloc_tree_world(Level *level, GameManager *manager, void *context)
@@ -52,11 +64,11 @@ const LevelBehaviour tree_level = {
     .context_size = sizeof(LevelContext), // size of level context, will be automatically allocated and freed
 };
 const LevelBehaviour example_level = {
-    .alloc = level_alloc_example_world,   // called once, when level allocated
-    .free = NULL,                         // called once, when level freed
-    .start = level_start,                 // called when level is changed to this level
-    .stop = NULL,                         // called when level is changed from this level
-    .context_size = sizeof(LevelContext), // size of level context, will be automatically allocated and freed
+    .alloc = level_alloc_example_world,
+    .free = NULL,
+    .start = level_start,
+    .stop = NULL,
+    .context_size = sizeof(LevelContext),
 };
 
 void level_alloc_world(Level *level, GameManager *manager, void *context)
@@ -69,70 +81,53 @@ void level_alloc_world(Level *level, GameManager *manager, void *context)
     player_spawn(level, manager);
 }
 
-bool level_load_all()
+bool level_load_all(GameManager *game_manager)
 {
     char file_path[128];
     snprintf(
         file_path,
         sizeof(file_path),
-        STORAGE_EXT_PATH_PREFIX "/apps_data/flip_world/worlds.json");
-
-    FuriString *world_data = flipper_http_load_from_file(file_path);
-    if (!world_data)
-    {
-        FURI_LOG_E(TAG, "Failed to load world data");
-        return false;
-    }
+        STORAGE_EXT_PATH_PREFIX "/apps_data/flip_world/worlds/world_list.json");
 
-    const char *json_data = furi_string_get_cstr(world_data);
-    if (!json_data)
+    FuriString *world_list = flipper_http_load_from_file(file_path);
+    if (!world_list)
     {
-        FURI_LOG_E(TAG, "Failed to get world data");
-        furi_string_free(world_data);
+        FURI_LOG_E(TAG, "Failed to load world list");
         return false;
     }
-
-    const LevelBehaviour new_behavior = {
-        .alloc = level_alloc_world,
-        .free = NULL,
-        .start = level_start,
-        .stop = NULL,
-        .context_size = sizeof(LevelContext),
-    };
-
     for (int i = 0; i < 10; i++)
     {
-        char *json = get_json_array_value("worlds", i, json_data);
-        if (!json)
+        FuriString *world_id = get_json_array_value_furi("names", i, world_list);
+        if (!world_id)
         {
-            FURI_LOG_E(TAG, "Failed to get worlds. Data likely empty");
+            FURI_LOG_E(TAG, "Failed to get world id");
             break;
         }
-
-        char *world_id = get_json_value("name", json);
-        if (!world_id)
+        snprintf(level_contexts[i].id, sizeof(level_contexts[i].id), "%s", furi_string_get_cstr(world_id));
+        level_contexts[i].index = i;
+        LevelBehaviour *new_behavior = malloc(sizeof(LevelBehaviour));
+        if (!new_behavior)
         {
-            FURI_LOG_E(TAG, "Failed to get world id");
-            furi_string_free(world_data);
-            free(json);
+            FURI_LOG_E(TAG, "Failed to allocate memory for level behavior");
+            furi_string_free(world_id);
+            furi_string_free(world_list);
             return false;
         }
-
-        snprintf(level_contexts[i].id, sizeof(level_contexts[i].id), "%s", "example_world");
-        // safely copy the i value to the index
-        level_contexts[i].index = i;
-        level_behaviors[i] = &new_behavior;
+        *new_behavior = (LevelBehaviour){
+            .alloc = level_alloc_world,
+            .free = NULL,
+            .start = level_start,
+            .stop = NULL,
+            .context_size = sizeof(LevelContext),
+        };
         level_count++;
-        free(json);
-        free(world_id);
+        game_manager_add_level(game_manager, new_behavior);
+        furi_string_free(world_id);
     }
-
-    furi_string_free(world_data);
+    furi_string_free(world_list);
     return true;
 }
 
-// array of LevelBehaviour structures
-const LevelBehaviour *level_behaviors[10] = {0};
 LevelContext level_contexts[] = {0};
 Level *levels[] = {0};
 int level_count = 0;

+ 2 - 3
game/level.h

@@ -8,12 +8,11 @@ typedef struct
 } LevelContext;
 
 extern Level *level_tree;
-extern Level *level_example;
 extern const LevelBehaviour tree_level;
+extern Level *level_example;
 extern const LevelBehaviour example_level;
-extern const LevelBehaviour *level_behaviors[10];
 extern LevelContext level_contexts[];
 extern Level *levels[];
 extern int level_count;
 
-bool level_load_all();
+bool level_load_all(GameManager *game_manager);

+ 43 - 28
game/world.c

@@ -57,45 +57,60 @@ bool draw_json_world_furi(Level *level, FuriString *json_data)
 {
     for (int i = 0; i < MAX_WORLD_OBJECTS; i++)
     {
-        char *data = get_json_array_value("json_data", i, furi_string_get_cstr(json_data));
+        FuriString *data = get_json_array_value_furi("json_data", i, json_data);
         if (data == NULL)
         {
             break;
         }
-        char *icon = get_json_value("icon", data);
-        char *x = get_json_value("x", data);
-        char *y = get_json_value("y", data);
-        char *width = get_json_value("width", data);
-        char *height = get_json_value("height", data);
-        char *amount = get_json_value("amount", data);
-        char *horizontal = get_json_value("horizontal", data);
-        if (icon == NULL || x == NULL || y == NULL || width == NULL || height == NULL || amount == NULL || horizontal == NULL)
+        FuriString *icon = get_json_value_furi("icon", data);
+        FuriString *x = get_json_value_furi("x", data);
+        FuriString *y = get_json_value_furi("y", data);
+        FuriString *width = get_json_value_furi("width", data);
+        FuriString *height = get_json_value_furi("height", data);
+        FuriString *amount = get_json_value_furi("amount", data);
+        FuriString *horizontal = get_json_value_furi("horizontal", data);
+        if (!icon || !x || !y || !width || !height || !amount || !horizontal)
         {
+            furi_string_free(data);
             return false;
         }
         // if amount is less than 2, we spawn a single icon
-        if (atoi(amount) < 2)
+        if (atoi(furi_string_get_cstr(amount)) < 2)
         {
-            spawn_icon(level, get_icon(icon), atoi(x), atoi(y), atoi(width), atoi(height));
-            free(data);
-            free(icon);
-            free(x);
-            free(y);
-            free(width);
-            free(height);
-            free(amount);
-            free(horizontal);
+            spawn_icon(
+                level,
+                get_icon_furi(icon),
+                atoi(furi_string_get_cstr(x)),
+                atoi(furi_string_get_cstr(y)),
+                atoi(furi_string_get_cstr(width)),
+                atoi(furi_string_get_cstr(height)));
+            furi_string_free(data);
+            furi_string_free(icon);
+            furi_string_free(x);
+            furi_string_free(y);
+            furi_string_free(width);
+            furi_string_free(height);
+            furi_string_free(amount);
+            furi_string_free(horizontal);
             continue;
         }
-        spawn_icon_line(level, get_icon(icon), atoi(x), atoi(y), atoi(width), atoi(height), atoi(amount), strcmp(horizontal, "true") == 0);
-        free(data);
-        free(icon);
-        free(x);
-        free(y);
-        free(width);
-        free(height);
-        free(amount);
-        free(horizontal);
+        spawn_icon_line(
+            level,
+            get_icon_furi(icon),
+            atoi(furi_string_get_cstr(x)),
+            atoi(furi_string_get_cstr(y)),
+            atoi(furi_string_get_cstr(width)),
+            atoi(furi_string_get_cstr(height)),
+            atoi(furi_string_get_cstr(amount)),
+            furi_string_cmp(horizontal, "true") == 0);
+        furi_string_free(data);
+        furi_string_free(icon);
+        furi_string_free(x);
+        furi_string_free(y);
+        furi_string_free(width);
+        furi_string_free(height);
+        furi_string_free(amount);
+        furi_string_free(horizontal);
     }
     return true;
 }