eden-miror/src/common
crueter 39f226a853
[qt] Ryujinx save data link (#2815)
This adds an action to the Game List context menu that lets users link
save data from Eden to Ryujinx, or vice versa.

Unfortunately, this isn't so simple to deal with due to the way Ryujinx's saves work. Ryujinx stores its saves in the... config directory... in `bis/user/save`. Unlike Yuzu, however, it doesn't store things by TitleID, instead it's just a bunch of directories from 000...01 to 000...0f and so on. The way it *maps* TitleID to SaveID is via `imkvdb.arc` in `bis/system/save/8000000000000000/0/` and also an identical copy in the `1` directory for... some reason. `imkvdb.arc` is handled by `FlatMapKeyValueStore` in LibHac, which, as the name implies, is a key-value storage system that `imkvdb.arc`, and seemingly `imkvdb.arc` alone, uses. The way this class is written is really weird, almost as if it's designed to accommodate more types of kvdbs... but for now we can safely assume that there aren't gonna be any other `kvdb` implementations added to HorizonNX.

Regardless, the file format is ridiculously simple so I didn't actually need to do a deep dive into C# code... of which I can basically only read Avalonia. A simple `xxd` on the `imkvdb.arc` is all that's needed, and here's everything that matters:
- The `IMKV` magic header (4 bytes)
- 8 bytes that don't really have anything useful to us, except for a size byte (presumably a `u32`) strewn at offset `0x08` from the start of the file, which is useless to us
- Then we start the `IMEN` list. I don't know what the `IM` stands for, but `IMEN` is just, well, an ENtry. Offsets shown are relative to the start of the `IMEN` header.
  * 4-byte `IMEN` magic header at 0x0
  * 8 bytes of filler data. It contains two `0x40` bytes, but I'm not really sure what they do
  * TitleID (u64) at `0xC`, for example `00a0 df10  501f 0001` for Legends: Arceus (the byte order is swapped)
  * 0x38 bytes of filler starting at offset 0x14
  * SaveID (u64) at `0x4C`, for example `0a00 0000 0000 0000` for my Legends: Arceus save
  * 0x38 bytes of filler starting at offset 0x54

Full example for Legends: Arceus:
```
000001b0: 494d 454e 4000 0000 4000 0000 00a0 df10  IMEN@...@.......
000001c0: 501f 0001 0100 0000 0000 0000 0000 0000  P...............
000001d0: 0000 0000 0000 0000 0000 0000 0100 0000  ................
000001e0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000001f0: 0000 0000 0000 0000 0000 0000 0a00 0000  ................
00000200: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000210: 0000 0000 0100 0000 0000 0000 0000 0000  ................
00000220: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000230: 0000 0000 0000 0000 0000 0000 494d 454e  ............IMEN
```
Ultimately, the size of the `IMEN` sits at 0x8C or 140 bytes. With this knowledge reading all the TitleID -> SaveID pairs is basically free, and outside of validation and stuff is like 15 lines of relevant code. Some interesting caveats, though:
- There are two entries for some TitleIDs for... some reason? Ignoring the second one seems to work though.
- Within each save directory, there are directories `0` and `1`... and only `0` ever seems used??? It's where Ryujinx points you to for save, so I just chose to use that.

Once everything is parsed, the rest of the implementation is extremely trivial:
- When the user requests a Ryujinx link, match the current program_id to the corresponding SaveID in `imkvdb`
- If it doesn't exist, just error out (save data is probably nonexistent)
- If it does though, give the user the option to use Eden's current save data OR Ryujinx's current save data.

Old save data is deleted depending on which one you chose.

Signed-off-by: crueter <crueter@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2815
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2025-10-28 03:46:47 +01:00
..
android [android] input over(lay)haul 2: Individual scaling of buttons (#2562) 2025-09-29 22:38:26 +02:00
arm64 Rework time service to fix time passing offline. 2024-01-24 04:26:55 +00:00
fs [qt] Ryujinx save data link (#2815) 2025-10-28 03:46:47 +01:00
linux general: conditionally compile gamemode on linux only 2023-11-29 14:26:11 -05:00
logging [logging, debugger] remove unescesary logic and only query USER env variable once (#2800) 2025-10-27 20:55:01 +01:00
windows timer_resolution: Set current process to High QoS 2023-03-05 02:36:31 -05:00
x64 [meta] fix license headers (#2547) 2025-09-21 21:58:59 +02:00
address_space.cpp general: Format licenses as per SPDX guidelines 2022-10-06 21:00:54 +02:00
address_space.h Move to Clang Format 15 2023-01-29 17:49:42 -07:00
address_space.inc Fix address space allocator slow path to avoid OOB 2023-05-07 15:11:16 +01:00
algorithm.h General: Fix compilation for GCC 2022-10-06 21:00:53 +02:00
alignment.h fssystem: rework for yuzu style 2023-08-15 17:47:40 -04:00
announce_multiplayer_room.h Fix License headers & CI (#168) 2025-06-09 01:40:21 +00:00
assert.cpp assert/logging: Stop the logging thread and flush the backends before crashing 2023-12-26 10:35:14 +01:00
assert.h Enable compiler optimizations and enforce x86-64-v2 on GCC/Clang (#9442) 2022-12-17 17:16:52 -08:00
atomic_helpers.h Move to Clang Format 15 2023-01-29 17:49:42 -07:00
atomic_ops.h atomic_ops: Fix MSVC 2024-01-27 21:42:16 +00:00
bit_field.h externals: Update to fmt 10 and add format_as formatter for BitField 2023-05-28 15:05:55 -04:00
bit_util.h Move to Clang Format 15 2023-01-29 17:49:42 -07:00
bounded_threadsafe_queue.h [common] use libc++ provided jthread instead of in-house one (which deadlocks on FBSD 14) (#351) 2025-10-01 06:59:35 +02:00
cityhash.cpp chore: add missing SPDX tags 2022-04-28 18:24:11 +02:00
cityhash.h chore: add missing SPDX tags 2022-04-28 18:24:11 +02:00
CMakeLists.txt [qt] Ryujinx save data link (#2815) 2025-10-28 03:46:47 +01:00
common_funcs.h Make system settings persistent across boots 2023-12-16 06:01:54 +00:00
common_types.h [tools, cmake] refactor: update/hash check scripts, use tags for some more deps, proper CPMUtil separation (#2666) 2025-10-05 03:04:53 +02:00
concepts.h Move to Clang Format 15 2023-01-29 17:49:42 -07:00
container_hash.h container_hash: use climits 2023-03-26 10:24:33 -04:00
demangle.cpp [compat] Solaris build fixes for openssl, catch2; NetBSD build fixes (#2752) 2025-10-17 22:12:58 +02:00
demangle.h Move demangle impl to cpp 2023-01-14 05:12:41 +00:00
detached_tasks.cpp general: Silence -Wshadow{,-uncaptured-local} warnings 2023-07-18 19:31:35 -04:00
detached_tasks.h chore: make yuzu REUSE compliant 2022-07-27 12:53:49 +02:00
device_power_state.cpp Add Device Power State (Windows, Linux, Mac and Android) (#197) 2025-06-18 08:34:54 +00:00
device_power_state.h Add Device Power State (Windows, Linux, Mac and Android) (#197) 2025-06-18 08:34:54 +00:00
div_ceil.h Move to Clang Format 15 2023-01-29 17:49:42 -07:00
dynamic_library.cpp Update fmt to allow for v11 2025-04-10 01:11:22 +02:00
dynamic_library.h common: dynamic_library: Add ctor for existing handle. 2023-06-03 00:05:31 -07:00
elf.h jit: add support for relr-type relocations 2023-10-11 11:13:19 -04:00
error.cpp common: error: Fix for Android. 2023-06-03 00:05:27 -07:00
error.h chore: make yuzu REUSE compliant 2022-07-27 12:53:49 +02:00
expected.h Move to Clang Format 15 2023-01-29 17:49:42 -07:00
fiber.cpp Revert "Disabled MCO_USE_VMEM_ALLOCATOR because standard stack size seems to suffice" 2025-04-06 22:52:55 -03:00
fiber.h Implemented rewindless Fiber without Boost (using minicoro) 2025-04-04 03:40:47 +02:00
fixed_point.h general: fix spelling mistakes 2023-03-12 11:33:01 -04:00
free_region_manager.h [meta] fix license headers (#2547) 2025-09-21 21:58:59 +02:00
hash.h Refactor VideoCore to use AS sepparate from Channel. 2022-10-06 21:00:52 +02:00
heap_tracker.cpp [meta] fix license headers (#2547) 2025-09-21 21:58:59 +02:00
heap_tracker.h Revert "[heap_tracker] Use ankerl map instead of rb tree (#249)" (#382) 2025-09-04 16:04:42 +02:00
hex_util.cpp chore: add missing SPDX tags 2022-04-28 18:24:11 +02:00
hex_util.h Update fmt to allow for v11 2025-04-10 01:11:22 +02:00
host_memory.cpp [compat] HaikuOS port (#2805) 2025-10-22 04:53:40 +02:00
host_memory.h core: track separate heap allocation for linux 2023-12-25 23:30:56 -05:00
input.h input_common: Remove duplicated DriverResult enum 2023-06-28 09:49:47 -06:00
intrusive_list.h common: add intrusive list type 2023-04-29 17:46:26 -04:00
intrusive_red_black_tree.h general: fixes for gcc 13 2023-04-02 19:02:04 -04:00
literals.h general: Convert source file copyright comments over to SPDX 2022-04-23 05:55:32 -04:00
lru_cache.h general: Convert source file copyright comments over to SPDX 2022-04-23 05:55:32 -04:00
lz4_compression.cpp fssystem: rework for yuzu style 2023-08-15 17:47:40 -04:00
lz4_compression.h fssystem: rework for yuzu style 2023-08-15 17:47:40 -04:00
make_unique_for_overwrite.h Move to Clang Format 15 2023-01-29 17:49:42 -07:00
math_util.h [meta] fix license headers (#2547) 2025-09-21 21:58:59 +02:00
memory_detect.cpp general: Convert source file copyright comments over to SPDX 2022-04-23 05:55:32 -04:00
memory_detect.h Rework time service to fix time passing offline. 2024-01-24 04:26:55 +00:00
minicoro.h [build, cmake] port to solaris (#96) 2025-07-23 10:00:29 +02:00
multi_level_page_table.cpp general: Format licenses as per SPDX guidelines 2022-10-06 21:00:54 +02:00
multi_level_page_table.h General: address feedback 2022-10-06 21:00:54 +02:00
multi_level_page_table.inc general: Format licenses as per SPDX guidelines 2022-10-06 21:00:54 +02:00
overflow.h [common] replace Common::BitCast with libc++ provided one (#2774) 2025-10-22 02:56:28 +02:00
page_table.cpp scope_exit: Make constexpr 2024-02-19 16:00:46 +01:00
page_table.h kernel: add KPageTableBase 2023-11-10 12:01:35 -05:00
param_package.cpp chore: make yuzu REUSE compliant 2022-07-27 12:53:49 +02:00
param_package.h chore: make yuzu REUSE compliant 2022-07-27 12:53:49 +02:00
parent_of_member.h Silence std::aligned_storage warnings as it's deprecated in C++23, 2022-09-01 16:50:41 +01:00
point.h general: Convert source file copyright comments over to SPDX 2022-04-23 05:55:32 -04:00
polyfill_thread.h [common] use libc++ provided jthread instead of in-house one (which deadlocks on FBSD 14) (#351) 2025-10-01 06:59:35 +02:00
quaternion.h chore: make yuzu REUSE compliant 2022-07-27 12:53:49 +02:00
range_map.h [meta] fix license headers (#2547) 2025-09-21 21:58:59 +02:00
range_mutex.h smmu: use new range mutex construction for protecting counters 2024-01-31 16:38:51 +01:00
range_sets.h Common: Rename SplitRangeSet to OverlapRangeSet 2024-02-05 23:01:17 +01:00
range_sets.inc [cmake] enable clang-cl and WoA builds (#348) 2025-09-09 20:47:49 +02:00
ring_buffer.h [cmake] enable clang-cl and WoA builds (#348) 2025-09-09 20:47:49 +02:00
scm_rev.cpp.in [fixup] fix bad variable names (#2642) 2025-10-01 16:36:07 +02:00
scm_rev.h [meta] allow customisation of auto-updater, remove hardcoded title names and fix dup title names (#2588) 2025-10-01 05:07:59 +02:00
scope_exit.h scope_exit: Make constexpr 2024-02-19 16:00:46 +01:00
scratch_buffer.h Fix ScratchBuffer moves 2023-07-04 16:02:58 +01:00
settings.cpp [compat] HaikuOS port (#2805) 2025-10-22 04:53:40 +02:00
settings.h [compat] HaikuOS port (#2805) 2025-10-22 04:53:40 +02:00
settings_common.cpp Fix more typos 2024-01-15 23:26:53 +00:00
settings_common.h Add dynamic state extension configs 2025-04-23 20:57:53 -04:00
settings_enums.h [compat] Solaris build fixes for openssl, catch2; NetBSD build fixes (#2752) 2025-10-17 22:12:58 +02:00
settings_input.cpp core: hid: Split SL and SR buttons 2023-11-11 21:03:15 -06:00
settings_input.h android: Input mapping 2024-02-17 12:32:33 -05:00
settings_setting.h [common] No need to specify min/max for settings; fix crash when OOB value is given for some settings (#2609) 2025-09-29 18:40:29 +02:00
signal_chain.cpp android: Add cpu bakend gui toggle 2023-11-25 00:47:28 -05:00
signal_chain.h Address some review comments 2023-11-25 00:47:35 -05:00
slot_vector.h [compat] Debian stable gcc12/clang14 compilation fixes (#2763) 2025-10-18 01:54:43 +02:00
socket_types.h ssl: Reorder inclusions 2023-07-17 15:46:24 -04:00
spin_lock.cpp general: Convert source file copyright comments over to SPDX 2022-04-23 05:55:32 -04:00
spin_lock.h general: Convert source file copyright comments over to SPDX 2022-04-23 05:55:32 -04:00
stb.cpp cmake: prefer system stb headers 2023-10-25 21:47:32 +02:00
stb.h cmake: prefer system stb headers 2023-10-25 21:47:32 +02:00
steady_clock.cpp (wall, native)_clock: Rework NativeClock 2023-06-07 21:44:42 -04:00
steady_clock.h steady_clock: Introduce a real time clock 2023-03-07 21:17:46 -05:00
stream.cpp general: Convert source file copyright comments over to SPDX 2022-04-23 05:55:32 -04:00
stream.h general: Convert source file copyright comments over to SPDX 2022-04-23 05:55:32 -04:00
string_util.cpp [common, fs] Use std::string_view instead of std::string&; inline functions that are used rarely (#330) 2025-08-27 22:21:04 +02:00
string_util.h [common, fs] include missing header introduced on #330 (#370) 2025-08-31 08:40:46 +02:00
swap.h Warnings cleanup for GCC 13 and Clang 16 2023-08-25 19:22:31 -04:00
thread.cpp [compat] HaikuOS port (#2805) 2025-10-22 04:53:40 +02:00
thread.h [common] use libc++ provided jthread instead of in-house one (which deadlocks on FBSD 14) (#351) 2025-10-01 06:59:35 +02:00
thread_queue_list.h chore: add missing SPDX tags 2022-04-28 18:24:11 +02:00
thread_worker.h [common] use libc++ provided jthread instead of in-house one (which deadlocks on FBSD 14) (#351) 2025-10-01 06:59:35 +02:00
threadsafe_queue.h [common] use libc++ provided jthread instead of in-house one (which deadlocks on FBSD 14) (#351) 2025-10-01 06:59:35 +02:00
time_zone.cpp Rework time service to fix time passing offline. 2024-01-24 04:26:55 +00:00
time_zone.h common: Move system time zone string detection 2023-06-05 15:15:11 -04:00
tiny_mt.h [meta] fix license headers (#2547) 2025-09-21 21:58:59 +02:00
tree.h [common] Use U8 for colour of RB-tree instead of integer to save space (#228) 2025-08-15 23:21:15 +02:00
typed_address.h Update fmt to allow for v11 2025-04-10 01:11:22 +02:00
uint128.h [meta] fix license headers (#2547) 2025-09-21 21:58:59 +02:00
unique_function.h general: Convert source file copyright comments over to SPDX 2022-04-23 05:55:32 -04:00
uuid.cpp Update fmt to allow for v11 2025-04-10 01:11:22 +02:00
uuid.h [desktop, core] yuzu -> Eden, eden -> Eden 2025-07-19 00:12:21 -04:00
vector_math.h [vector_math]: Use NEON intrinsics in Vec4 dot operation (#177) 2025-08-02 01:48:04 +02:00
virtual_buffer.cpp [compat] HaikuOS port (#2805) 2025-10-22 04:53:40 +02:00
virtual_buffer.h general: Convert source file copyright comments over to SPDX 2022-04-23 05:55:32 -04:00
wall_clock.cpp Rework time service to fix time passing offline. 2024-01-24 04:26:55 +00:00
wall_clock.h Rework time service to fix time passing offline. 2024-01-24 04:26:55 +00:00
zstd_compression.cpp zstd: Use ZSTD_getFrameContentSize instead of ZSTD_getDecompressedSize 2023-03-23 22:16:20 -04:00
zstd_compression.h general: Convert source file copyright comments over to SPDX 2022-04-23 05:55:32 -04:00