Skip to content

Commit

Permalink
Add an "Import Save File" and "Export Save File" button in the menu bar.
Browse files Browse the repository at this point in the history
  • Loading branch information
Arignir committed Mar 17, 2024
1 parent 5a7b3da commit c896af6
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 9 deletions.
3 changes: 2 additions & 1 deletion include/app/app.h
Original file line number Diff line number Diff line change
Expand Up @@ -498,14 +498,15 @@ void app_config_push_recent_rom(struct app *app, char const *path);

/* emulator.c */
void app_emulator_process_all_notifs(struct app *app);
bool app_emulator_configure_and_run(struct app *app, char const *rom_path);
bool app_emulator_configure_and_run(struct app *app, char const *rom_path, char const *backup_to_import);
void app_emulator_reset(struct app *app);
void app_emulator_stop(struct app *app);
void app_emulator_run(struct app *app);
void app_emulator_pause(struct app *app);
void app_emulator_exit(struct app *app);
void app_emulator_key(struct app *app, enum keys key, bool pressed);
void app_emulator_settings(struct app *app);
void app_emulator_export_save_to_path(struct app *app, char const *);
void app_emulator_update_backup(struct app *app);
void app_emulator_screenshot(struct app *app);
void app_emulator_screenshot_path(struct app *app, char const *);
Expand Down
130 changes: 125 additions & 5 deletions source/app/emulator.c
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,7 @@ app_emulator_configure_rom(

static
bool
app_emulator_configure_backup(
app_emulator_configure_backupe_storage(
struct app *app,
char const *backup_path
) {
Expand Down Expand Up @@ -458,7 +458,76 @@ app_emulator_configure_backup(
app->emulation.launch_config->backup_storage.data = data;
app->emulation.launch_config->backup_storage.size = file_len;
} else {
logln(HS_WARNING, "Failed to open the save file. A new one is created instead.");
logln(HS_WARNING, "Failed to open the save file. A new one will be created instead.");

app->emulation.backup_file = hs_fopen(backup_path, "wb+");

if (!app->emulation.backup_file) {
app_new_notification(
app,
UI_NOTIFICATION_ERROR,
"Failed to create %s: %s.",
backup_path,
strerror(errno)
);
return (true);
}
}
return (false);
}

static
bool
app_emulator_import_backup_storage(
struct app *app,
char const *backup_path_to_import,
char const *backup_path
) {
size_t file_len;
size_t read_len;
FILE *backup;
void *data;


backup = hs_fopen(backup_path_to_import, "rb");
if (!backup) {
app_new_notification(
app,
UI_NOTIFICATION_ERROR,
"Failed to import save file %s: %s.",
backup_path_to_import,
strerror(errno)
);
return (true);
}

fseek(backup, 0, SEEK_END);
file_len = ftell(backup);
rewind(backup);

data = calloc(1, file_len);
hs_assert(data);

read_len = fread(data, 1, file_len, backup);

if (read_len != file_len) {
logln(HS_WARNING, "Failed to import the save file. Is it corrupted?");
} else {
app_new_notification(
app,
UI_NOTIFICATION_SUCCESS,
"Save file successfully imported.",
backup_path_to_import,
strerror(errno)
);
}

app->emulation.launch_config->backup_storage.data = data;
app->emulation.launch_config->backup_storage.size = file_len;
app->emulation.backup_file = hs_fopen(backup_path, "rb+");

if (!app->emulation.backup_file) {
logln(HS_WARNING, "Failed to open the save file. A new one will be created instead.");

app->emulation.backup_file = hs_fopen(backup_path, "wb+");

Expand Down Expand Up @@ -487,11 +556,14 @@ app_emulator_configure_backup(
** - Reset the emulator
** - Wait for the reset notification
** - Run/Pause the emulator, according to the configuration
**
** NOTE: `backup_to_import` can be NULL if there is no backup to import.
*/
bool
app_emulator_configure_and_run(
struct app *app,
char const *rom_path
char const *rom_path,
char const *backup_to_import
) {
struct message_reset event;
char *backup_path;
Expand Down Expand Up @@ -543,7 +615,7 @@ app_emulator_configure_and_run(

if (app_emulator_configure_bios(app)
|| (is_archive ? app_emulator_configure_rom_archive(app, rom_path) : app_emulator_configure_rom(app, rom_path))
|| app_emulator_configure_backup(app, backup_path)
|| (backup_to_import ? app_emulator_import_backup_storage(app, backup_to_import, backup_path) : app_emulator_configure_backupe_storage(app, backup_path))
) {
app_emulator_unconfigure(app);
return (true);
Expand Down Expand Up @@ -644,7 +716,7 @@ app_emulator_reset(
char *game_path;

game_path = strdup(app->emulation.game_path);
app_emulator_configure_and_run(app, game_path);
app_emulator_configure_and_run(app, game_path, NULL);
free(game_path);
}

Expand Down Expand Up @@ -783,6 +855,54 @@ app_emulator_update_backup(
app->emulation.gba->shared_data.backup_storage.dirty = false;
}

/*
** Write the content of the backup storage on the disk, regardless if it's dirty or not.
*/
void
app_emulator_export_save_to_path(
struct app *app,
char const *path
) {
FILE *file;

if (app->emulation.gba->shared_data.backup_storage.data) {
file = hs_fopen(path, "wb");

if (!file) {
goto error;
}

if (
fwrite(
app->emulation.gba->shared_data.backup_storage.data,
app->emulation.gba->shared_data.backup_storage.size,
1,
file
) != 1
) {
goto error;
}

app_new_notification(
app,
UI_NOTIFICATION_SUCCESS,
"Save file exported to \"%s\"",
path
);
}

return;

error:
app_new_notification(
app,
UI_NOTIFICATION_ERROR,
"Failed to export the save file to \"%s\": %s",
path,
strerror(errno)
);
}

/*
** Take a screenshot of the game and writes it to the disk.
*/
Expand Down
2 changes: 1 addition & 1 deletion source/app/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ main(
);

if (app.args.rom_path) {
app_emulator_configure_and_run(&app, app.args.rom_path);
app_emulator_configure_and_run(&app, app.args.rom_path, NULL);
}

#ifdef WITH_DEBUGGER
Expand Down
45 changes: 43 additions & 2 deletions source/app/windows/menubar.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ app_win_menubar_file(
);

if (result == NFD_OKAY) {
app_emulator_configure_and_run(app, path);
app_emulator_configure_and_run(app, path, NULL);
NFD_FreePath(path);
}
}
Expand All @@ -51,7 +51,7 @@ app_win_menubar_file(
// the path to a safe space first.
path = strdup(app->file.recent_roms[x]);

app_emulator_configure_and_run(app, path);
app_emulator_configure_and_run(app, path, NULL);

free(path);
}
Expand Down Expand Up @@ -196,6 +196,47 @@ app_win_menubar_emulation(

igSeparator();

if (igMenuItem_Bool("Import Save File", NULL, false, app->emulation.is_started && (bool)app->emulation.gba->shared_data.backup_storage.data)) {
nfdresult_t result;
nfdchar_t *path;

result = NFD_OpenDialog(
&path,
(nfdfilteritem_t[1]){(nfdfilteritem_t){ .name = "GBA Save File", .spec = "sav"}},
1,
NULL
);

if (result == NFD_OKAY) {
char *game_path;

game_path = strdup(app->emulation.game_path);
app_emulator_configure_and_run(app, game_path, path);
free(game_path);
NFD_FreePath(path);
}
}

if (igMenuItem_Bool("Export Save File", NULL, false, app->emulation.is_started && (bool)app->emulation.gba->shared_data.backup_storage.data)) {
nfdresult_t result;
nfdchar_t *path;

result = NFD_SaveDialog(
&path,
(nfdfilteritem_t[1]){(nfdfilteritem_t){ .name = "GBA Save File", .spec = "sav"}},
1,
NULL,
NULL
);

if (result == NFD_OKAY) {
app_emulator_export_save_to_path(app, path);
NFD_FreePath(path);
}
}

igSeparator();

bind = SDL_GetKeyName(app->binds.keyboard[BIND_EMULATOR_PAUSE]);
if (igMenuItem_Bool("Pause", bind ?: "", !app->emulation.is_running, app->emulation.is_started)) {
if (app->emulation.is_running) {
Expand Down

0 comments on commit c896af6

Please sign in to comment.