Resource files
Source: src/dungeon_files.c · 90 lines · 2 functions.
Module responsibility
Initialises the Dungeon resource folder and installs required files when they are missing.
Module entry points
These functions are exposed to the rest of the Dungeon system. Open one to follow its decisions and helper calls.
How to read these diagrams
Each function has an expandable structural diagram derived from the current C source. Decisions split into True and False, loop bodies are indented, and arrows show statement order.
These are source diagrams before preprocessing, not runtime traces. Callback execution, task scheduling and macro expansion are not inferred.
Functions in this file
copyIfMissing() · source line 24
static bool copyIfMissing(const DungeonFileMigration *migration)
- Execute
FILE *destination = fopen(migration->new_path, "rb"); - Decision
destination != NULLTrue- Execute
fclose(destination); - Exit this function
return true;
FalseContinue after this decision.
- Execute
FILE *source = fopen(migration->old_path, "rb"); - Decision
source == NULLTrue- Exit this function
return true;
FalseContinue after this decision.
- Execute
char temporary_path[48]; - Execute
const int path_length = snprintf(temporary_path, sizeof(temporary_path), "%s.tmp", migration->new_path); - Decision
path_length <= 0 || (size_t)path_length >= sizeof(temporary_path)True- Execute
fclose(source); - Exit this function
return false;
FalseContinue after this decision.
- Execute
destination = fopen(temporary_path, "wb"); - Decision
destination == NULLTrue- Execute
fclose(source); - Exit this function
return false;
FalseContinue after this decision.
- Execute
bool copied = true; - Execute
uint8_t buffer[256]; - Execute
size_t count; - WHILE loop
(count = fread(buffer, 1, sizeof(buffer), source)) > 0URepeat body while the loop condition permits; then continue below.
- Decision
fwrite(buffer, 1, count, destination) != countTrue- Execute
copied = false; - Exit enclosing loop or switch
break;
FalseContinue after this decision.
- Decision
ferror(source) != 0True- Execute
copied = false;
FalseContinue after this decision.
- Execute
fclose(destination); - Execute
fclose(source); - Decision
!copiedTrue- Execute
remove(temporary_path); - Exit this function
return false;
FalseContinue after this decision.
- Decision
rename(temporary_path, migration->new_path) != 0True- Execute
remove(temporary_path); - Exit this function
return false;
FalseContinue after this decision.
- Execute
ESP_LOGI(TAG, "Copied %s to internal storage", migration->old_path); - Exit this function
return copied;
Read original function source
static bool copyIfMissing(const DungeonFileMigration *migration)
{
FILE *destination = fopen(migration->new_path, "rb");
if (destination != NULL) {
fclose(destination);
return true;
}
FILE *source = fopen(migration->old_path, "rb");
if (source == NULL) return true;
char temporary_path[48];
const int path_length = snprintf(temporary_path, sizeof(temporary_path), "%s.tmp", migration->new_path);
if (path_length <= 0 || (size_t)path_length >= sizeof(temporary_path)) {
fclose(source);
return false;
}
destination = fopen(temporary_path, "wb");
if (destination == NULL) {
fclose(source);
return false;
}
bool copied = true;
uint8_t buffer[256];
size_t count;
while ((count = fread(buffer, 1, sizeof(buffer), source)) > 0U) {
if (fwrite(buffer, 1, count, destination) != count) {
copied = false;
break;
}
}
if (ferror(source) != 0) copied = false;
fclose(destination);
fclose(source);
if (!copied) {
remove(temporary_path);
return false;
}
if (rename(temporary_path, migration->new_path) != 0) {
remove(temporary_path);
return false;
}
ESP_LOGI(TAG, "Copied %s to internal storage", migration->old_path);
return copied;
}dungeonFilesInitialize() · source line 70
bool dungeonFilesInitialize(bool sd_available)
Calls into this documentation:
- Execute
const esp_vfs_spiffs_conf_t config = { .base_path = DUNGEON_DATA_MOUNT, .partition_label = DUNGEON_DATA_PARTITION, .max_files = 5, .format_if_mount_failed = false, }; - Execute
const esp_err_t result = esp_vfs_spiffs_register(&config); - Decision
result != ESP_OKTrue- Execute
ESP_LOGE(TAG, "SPIFFS mount failed: %s", esp_err_to_name(result)); - Exit this function
return false;
FalseContinue after this decision.
- Decision
!sd_availableTrue- Exit this function
return true;
FalseContinue after this decision.
- FOR loop
unsigned index = 0U; index < sizeof(migrations) / sizeof(migrations[0]); ++indexRepeat body while the loop condition permits; then continue below.
- Decision
!copyIfMissing(&migrations[index])True- Execute
ESP_LOGE(TAG, "Could not migrate %s", migrations[index].old_path); - Exit this function
return false;
FalseContinue after this decision.
- Exit this function
return true;
Read original function source
bool dungeonFilesInitialize(bool sd_available)
{
const esp_vfs_spiffs_conf_t config = {
.base_path = DUNGEON_DATA_MOUNT,
.partition_label = DUNGEON_DATA_PARTITION,
.max_files = 5,
.format_if_mount_failed = false,
};
const esp_err_t result = esp_vfs_spiffs_register(&config);
if (result != ESP_OK) {
ESP_LOGE(TAG, "SPIFFS mount failed: %s", esp_err_to_name(result));
return false;
}
if (!sd_available) return true;
for (unsigned index = 0U; index < sizeof(migrations) / sizeof(migrations[0]); ++index)
if (!copyIfMissing(&migrations[index])) {
ESP_LOGE(TAG, "Could not migrate %s", migrations[index].old_path);
return false;
}
return true;
}Complete original file, including constants and data
/* Coded By JD(2026) */
#error "Reference listing only — not provided as build-ready source."
#include "dungeon_files.h"
#include "esp_log.h"
#include "esp_spiffs.h"
#include <stdio.h>
#include <stdint.h>
#define DUNGEON_DATA_MOUNT "/spiffs"
#define DUNGEON_DATA_PARTITION "assets"
static const char *TAG = "dungeon_files";
typedef struct {
const char *old_path;
const char *new_path;
} DungeonFileMigration;
static const DungeonFileMigration migrations[] = {
{ "/sdcard/dungeon/dungeon.dat", DUNGEON_DATA_MOUNT "/dungeon.dat" },
{ "/sdcard/dungeon/player.dat", DUNGEON_DATA_MOUNT "/dungeon_player.dat" },
{ "/sdcard/dungeon/explored.dat", DUNGEON_DATA_MOUNT "/dungeon_explored.dat" },
{ "/sdcard/dungeon/highscores.dat", DUNGEON_DATA_MOUNT "/dungeon_highscores.dat" },
};
static bool copyIfMissing(const DungeonFileMigration *migration)
{
FILE *destination = fopen(migration->new_path, "rb");
if (destination != NULL) {
fclose(destination);
return true;
}
FILE *source = fopen(migration->old_path, "rb");
if (source == NULL) return true;
char temporary_path[48];
const int path_length = snprintf(temporary_path, sizeof(temporary_path), "%s.tmp", migration->new_path);
if (path_length <= 0 || (size_t)path_length >= sizeof(temporary_path)) {
fclose(source);
return false;
}
destination = fopen(temporary_path, "wb");
if (destination == NULL) {
fclose(source);
return false;
}
bool copied = true;
uint8_t buffer[256];
size_t count;
while ((count = fread(buffer, 1, sizeof(buffer), source)) > 0U) {
if (fwrite(buffer, 1, count, destination) != count) {
copied = false;
break;
}
}
if (ferror(source) != 0) copied = false;
fclose(destination);
fclose(source);
if (!copied) {
remove(temporary_path);
return false;
}
if (rename(temporary_path, migration->new_path) != 0) {
remove(temporary_path);
return false;
}
ESP_LOGI(TAG, "Copied %s to internal storage", migration->old_path);
return copied;
}
bool dungeonFilesInitialize(bool sd_available)
{
const esp_vfs_spiffs_conf_t config = {
.base_path = DUNGEON_DATA_MOUNT,
.partition_label = DUNGEON_DATA_PARTITION,
.max_files = 5,
.format_if_mount_failed = false,
};
const esp_err_t result = esp_vfs_spiffs_register(&config);
if (result != ESP_OK) {
ESP_LOGE(TAG, "SPIFFS mount failed: %s", esp_err_to_name(result));
return false;
}
if (!sd_available) return true;
for (unsigned index = 0U; index < sizeof(migrations) / sizeof(migrations[0]); ++index)
if (!copyIfMissing(&migrations[index])) {
ESP_LOGE(TAG, "Could not migrate %s", migrations[index].old_path);
return false;
}
return true;
}