From dde9bf33552bd72940f55fdbe99ada3d95ef8306 Mon Sep 17 00:00:00 2001 From: konstantysz Date: Tue, 21 Oct 2025 21:55:32 +0200 Subject: [PATCH 1/7] Update DeSmuME submodule to konstantysz fork with backup import/export API --- .gitmodules | 2 +- desmume_src | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index ce88793..ebe748d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "desmume_src"] path = desmume_src - url = https://github.com/SkyTemple/desmume.git + url = https://github.com/konstantysz/desmume.git diff --git a/desmume_src b/desmume_src index 821c2a0..353c4b9 160000 --- a/desmume_src +++ b/desmume_src @@ -1 +1 @@ -Subproject commit 821c2a041048865924b1cfc925533020fc0d1618 +Subproject commit 353c4b92e23c80c987180e628bd6f025361aeb9a From 5874f41bb817d16d9a473f6bd76599388fbdd638 Mon Sep 17 00:00:00 2001 From: konstantysz Date: Tue, 21 Oct 2025 22:02:32 +0200 Subject: [PATCH 2/7] Add Python bindings for backup memory import/export --- desmume/emulator.py | 76 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/desmume/emulator.py b/desmume/emulator.py index bc994fe..8d778fd 100644 --- a/desmume/emulator.py +++ b/desmume/emulator.py @@ -248,6 +248,76 @@ def date(self, slot_id: int) -> str: return str(self.emu.lib.desmume_savestate_slot_date(slot_id), 'utf-8') +class DeSmuME_Backup: + """ + Import and export battery save files (backup memory). + Supports multiple formats: .sav (raw), .dsv (DeSmuME), .duc (Action Replay), .dss (DSOrganize). + + Should not be instantiated manually! + """ + def __init__(self, emu: 'DeSmuME'): + self.emu = emu + + def import_file(self, file_path: str) -> bool: + """ + Import battery save file (.sav, .dsv, .duc, etc.) + + Imports backup memory from a file. Supports multiple formats with automatic detection. + The emulator will automatically reset after successful import. + + :param file_path: Path to backup save file + :return: True if import succeeded, False otherwise + :raise: FileNotFoundError if the file doesn't exist + """ + if not os.path.exists(file_path): + raise FileNotFoundError(f"Backup file not found: {file_path}") + + self.emu.lib.desmume_backup_import_file.argtypes = [c_char_p] + self.emu.lib.desmume_backup_import_file.restype = c_int + + result = self.emu.lib.desmume_backup_import_file(c_char_p(strbytes(file_path))) + return bool(result) + + def import_raw(self, file_path: str, force_size: int = 0) -> bool: + """ + Import raw battery save with forced size. + + Similar to import_file() but allows forcing a specific backup device size. + Useful when auto-detection fails. + + :param file_path: Path to raw .sav file + :param force_size: Size in bytes (0 = auto-detect) + :return: True if import succeeded, False otherwise + :raise: FileNotFoundError if the file doesn't exist + """ + if not os.path.exists(file_path): + raise FileNotFoundError(f"Backup file not found: {file_path}") + + self.emu.lib.desmume_backup_import_raw.argtypes = [c_char_p, c_uint] + self.emu.lib.desmume_backup_import_raw.restype = c_int + + result = self.emu.lib.desmume_backup_import_raw( + c_char_p(strbytes(file_path)), + c_uint(force_size) + ) + return bool(result) + + def export_file(self, file_path: str) -> bool: + """ + Export current battery save to file. + + Saves the current backup memory to a .dsv file. + + :param file_path: Destination path for .dsv file + :return: True if export succeeded, False otherwise + """ + self.emu.lib.desmume_backup_export_file.argtypes = [c_char_p] + self.emu.lib.desmume_backup_export_file.restype = c_int + + result = self.emu.lib.desmume_backup_export_file(c_char_p(strbytes(file_path))) + return bool(result) + + class DeSmuME_Date(Structure): """A date C struct, to be used with setting a date for movie recording.""" _fields_ = [ @@ -983,6 +1053,7 @@ def __init__(self, dl_name: str = None): self._input = DeSmuME_Input(self) self._savestate = DeSmuME_Savestate(self) + self._backup = DeSmuME_Backup(self) self._movie = DeSmuME_Movie(self) self._memory = DeSmuME_Memory(self) self._sdl_window = None @@ -1018,6 +1089,11 @@ def savestate(self): """ return self._savestate + @property + def backup(self) -> DeSmuME_Backup: + """Battery save (backup memory) import/export.""" + return self._backup + @property def movie(self): """ From 473c58fb92748c36d3429d23a48ecc75020f162f Mon Sep 17 00:00:00 2001 From: konstantysz Date: Mon, 27 Oct 2025 22:05:01 +0100 Subject: [PATCH 3/7] Update to new API --- desmume/emulator.py | 27 ++------------------------- desmume_src | 2 +- 2 files changed, 3 insertions(+), 26 deletions(-) diff --git a/desmume/emulator.py b/desmume/emulator.py index 8d778fd..610d880 100644 --- a/desmume/emulator.py +++ b/desmume/emulator.py @@ -258,32 +258,9 @@ class DeSmuME_Backup: def __init__(self, emu: 'DeSmuME'): self.emu = emu - def import_file(self, file_path: str) -> bool: + def import_file(self, file_path: str, force_size: int = 0) -> bool: """ - Import battery save file (.sav, .dsv, .duc, etc.) - - Imports backup memory from a file. Supports multiple formats with automatic detection. - The emulator will automatically reset after successful import. - - :param file_path: Path to backup save file - :return: True if import succeeded, False otherwise - :raise: FileNotFoundError if the file doesn't exist - """ - if not os.path.exists(file_path): - raise FileNotFoundError(f"Backup file not found: {file_path}") - - self.emu.lib.desmume_backup_import_file.argtypes = [c_char_p] - self.emu.lib.desmume_backup_import_file.restype = c_int - - result = self.emu.lib.desmume_backup_import_file(c_char_p(strbytes(file_path))) - return bool(result) - - def import_raw(self, file_path: str, force_size: int = 0) -> bool: - """ - Import raw battery save with forced size. - - Similar to import_file() but allows forcing a specific backup device size. - Useful when auto-detection fails. + Import raw battery save. :param file_path: Path to raw .sav file :param force_size: Size in bytes (0 = auto-detect) diff --git a/desmume_src b/desmume_src index 353c4b9..49a9599 160000 --- a/desmume_src +++ b/desmume_src @@ -1 +1 @@ -Subproject commit 353c4b92e23c80c987180e628bd6f025361aeb9a +Subproject commit 49a9599ad48661553da0c9233b55bfc18efad78a From 22b720c595641cd35dcc4a6b3a8e3117d9463b81 Mon Sep 17 00:00:00 2001 From: konstantysz Date: Tue, 28 Oct 2025 22:34:14 +0100 Subject: [PATCH 4/7] Utilize new API --- desmume/emulator.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/desmume/emulator.py b/desmume/emulator.py index 610d880..79a636f 100644 --- a/desmume/emulator.py +++ b/desmume/emulator.py @@ -270,10 +270,10 @@ def import_file(self, file_path: str, force_size: int = 0) -> bool: if not os.path.exists(file_path): raise FileNotFoundError(f"Backup file not found: {file_path}") - self.emu.lib.desmume_backup_import_raw.argtypes = [c_char_p, c_uint] - self.emu.lib.desmume_backup_import_raw.restype = c_int + self.emu.lib.desmume_backup_import_file.argtypes = [c_char_p, c_uint] + self.emu.lib.desmume_backup_import_file.restype = c_int - result = self.emu.lib.desmume_backup_import_raw( + result = self.emu.lib.desmume_backup_import_file( c_char_p(strbytes(file_path)), c_uint(force_size) ) From 4d9ee952f4d477cf3cd98c52906be47a4b9c02dd Mon Sep 17 00:00:00 2001 From: konstantysz Date: Thu, 30 Oct 2025 13:36:41 +0100 Subject: [PATCH 5/7] Update DeSmuME submodule to upstream master with merged backup API --- desmume_src | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/desmume_src b/desmume_src index 49a9599..efd7486 160000 --- a/desmume_src +++ b/desmume_src @@ -1 +1 @@ -Subproject commit 49a9599ad48661553da0c9233b55bfc18efad78a +Subproject commit efd7486357ed1dbc0c6b4366b6676977b9296639 From dd4392e47c498afd2c9b29ae5c3bca7a66c80fe7 Mon Sep 17 00:00:00 2001 From: konstantysz Date: Thu, 30 Oct 2025 13:42:30 +0100 Subject: [PATCH 6/7] Update submodule to point to TASEmulators/desmume --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index ebe748d..fc2962f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "desmume_src"] path = desmume_src - url = https://github.com/konstantysz/desmume.git + url = https://github.com/TASEmulators/desmume.git From 2d1746beb4e1eadca0e9924cbeae3de1220dc528 Mon Sep 17 00:00:00 2001 From: konstantysz Date: Sat, 6 Dec 2025 21:54:04 +0100 Subject: [PATCH 7/7] Fix module commit --- .gitmodules | 2 +- desmume_src | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index fc2962f..ce88793 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "desmume_src"] path = desmume_src - url = https://github.com/TASEmulators/desmume.git + url = https://github.com/SkyTemple/desmume.git diff --git a/desmume_src b/desmume_src index efd7486..42ee6ea 160000 --- a/desmume_src +++ b/desmume_src @@ -1 +1 @@ -Subproject commit efd7486357ed1dbc0c6b4366b6676977b9296639 +Subproject commit 42ee6ea4c93416d1d77ddb2906f3a596ea8065ba