From 5cbe69388f40a9ae074b358ec49cf3ca8d6efb56 Mon Sep 17 00:00:00 2001 From: zhupengfei Date: Wed, 2 Oct 2019 20:06:39 +0800 Subject: [PATCH] Add support for config savegame --- README.md | 13 +++++-------- dist/threeSDumper.gm9 | 3 +++ src/core/importer.cpp | 39 +++++++++++++++++++++++++++++++++++++++ src/core/importer.h | 5 +++-- src/core/inner_fat.h | 12 ++++++------ 5 files changed, 56 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 07a0e23..738667c 100644 --- a/README.md +++ b/README.md @@ -34,10 +34,10 @@ If you are wishing to use threeSD with a portable install of Citra (i.e. that ha You will need to run a GodMode9 script. If you are unsure about the script's safety (which is good!), check the source code yourself [here](https://github.com/zhaowenlan1779/threeSD/blob/master/dist/threeSDumper.gm9). 1. Copy the gm9 script (`threeSDumper.gm9`) in `dist` to the `gm9/scripts` folder on your SD card. -1. Launch GodMode9 on your 3DS (you will need to hold a button corresponding to your `firm` file's name, or hold `START` to enter the chainloader menu). Press the `Home` button to bring up GodMode9's `HOME Menu`. Use the d-pad and the `A` button to select `Scripts...`. -1. Use the d-pad and the `A` button to select `threeSDumper`. You will be prompted with a question "Execute threeSD Dumper?". Press `A` to confirm. +1. Launch GodMode9 on your 3DS (you will need to hold a button corresponding to your `firm` file's name, or hold `START` to enter the chainloader menu). Press the `Home` button to bring up GodMode9's `HOME menu`. Use the D-pad and the `A` button to select `Scripts...`. +1. Use the D-pad and the `A` button to select `threeSDumper`. You will be prompted with a question "Execute threeSD Dumper?". Press `A` to confirm. 1. After a few seconds, you will see the message "Successfully dumped necessary files for threeSD." Your 3DS SD card is now prepared for use with threeSD and Citra. Press `A` to exit the script. -1. Power off your 3DS with `R+START`. Remove the SD card from your 3DS and insert it into your PC (with a card reader). +1. Power off your 3DS with GodMode9's `HOME menu`. Remove the SD card from your 3DS and insert it into your PC (with a card reader). ### On your PC @@ -46,22 +46,19 @@ Make sure the SD card is properly recognized and shows up as a disk. 1. Launch threeSD. You should see a small dialog, which has your SD card as an auto-detected configuration. * If it does not show up and the combo box says `None`, you should check if you can really find your SD card in the explorer (aka. `My Computer`), whether the drive for your SD card is accessible, and whether it contains the `Nintendo 3DS` and `threeSD` folders. 1. Click `OK`. After a few seconds of loading, you should see the `Select Contents` dialog. Select the contents you would like to import. By default, contents that do not currently exist is selected. Make sure the total size of your selected contents do not exceed the available space on your disk. - * You can select between `Title View` which organizes contents by title, and `Group View` which organizes contents by type (application, save data, etc). + * You can switch between `Title View` which organizes contents by title, and `Group View` which organizes contents by type (application, save data, etc). * The `System Archive` and `System Data` groups contains important data that is necessary for your imported games to run. You should definitely import the contents there, if they do not exist yet. 1. After you've finished your selection, click `OK`. You should now see a progress dialog; wait a while until your contents are imported. * The time will depend on how big your contents are, as well as your CPU processing power and (mainly) disk I/O speeds. ### What to do next -You can now enjoy your games with Citra, at high resolutions, with custom controllers, and the (now in Canary) Custom Textures feature! - -It is recommended that you also optionally [dump your config savegame](https://citra-emu.org/wiki/dumping-config-savegame-from-a-3ds-console) if you come across problems, for the best experience while enjoying Citra. +You can now enjoy your games with Citra, at high resolutions, with custom controllers and cheats, and the (now in Canary) custom textures! If you have any game cartidges, and would like to dump them as well, visit [this tutorial](https://citra-emu.org/wiki/dumping-game-cartridges). ## TODO -* Config savegame * UI improvements * Better error messages * Beautiful icons diff --git a/dist/threeSDumper.gm9 b/dist/threeSDumper.gm9 index c2cf61a..7e5d619 100644 --- a/dist/threeSDumper.gm9 +++ b/dist/threeSDumper.gm9 @@ -95,6 +95,9 @@ find 1:/title/000400db/00010302/content/*.app APP cp -w -n $[APP] $[OUT]/sysarchives/000400db/00010302.app decrypt $[OUT]/sysarchives/000400db/00010302.app +# Config savegame +cp -w -n 1:/data/$[SYSID0]/sysdata/00010017/00000000 $[OUT]/config.sav + set PREVIEW_MODE "threeSD Dumper\nby zhaowenlan1779\n \nSuccess!" echo "Successfully dumped necessary\nfiles for threeSD." diff --git a/src/core/importer.cpp b/src/core/importer.cpp index ba85dfa..16f45e2 100644 --- a/src/core/importer.cpp +++ b/src/core/importer.cpp @@ -239,6 +239,35 @@ bool SDMCImporter::ImportSysdata(u64 id, [[maybe_unused]] const ProgressCallback file.WriteString("slot0x25KeyX=" + Key::KeyToString(Key::GetKeyX(0x25)) + "\n"); return true; } + case 5: { // Config savegame + FileUtil::IOFile file(config.config_savegame_path, "rb"); + if (!file) { + return false; + } + + std::vector data(file.GetSize()); + if (file.ReadBytes(data.data(), data.size()) != data.size()) { + return false; + } + + DataContainer container(data); + if (!container.IsGood()) { + return false; + } + + SDSavegame save(std::move(container.GetIVFCLevel4Data())); + if (!save.IsGood()) { + return false; + } + + const auto target_path = + fmt::format("{}data/00000000000000000000000000000000/sysdata/00010017/00000000/", + FileUtil::GetUserPath(FileUtil::UserPath::NANDDir)); + if (!FileUtil::CreateFullPath(target_path)) { + return false; + } + return save.ExtractDirectory(target_path, 1); // 1 = root + } default: UNREACHABLE_MSG("Unexpected sysdata id {}", id); } @@ -445,6 +474,10 @@ void SDMCImporter::ListSysdata(std::vector& out) const { out.push_back( {ContentType::Sysdata, 4, FileUtil::Exists(sysdata_path + AES_KEYS), 47, AES_KEYS}); } + CHECK_CONTENT(5, config.config_savegame_path, + fmt::format("{}data/00000000000000000000000000000000/sysdata/00010017/", + FileUtil::GetUserPath(FileUtil::UserPath::NANDDir)), + "Config savegame"); } #undef CHECK_CONTENT @@ -545,6 +578,11 @@ void SDMCImporter::DeleteSysdata(u64 id) const { case 4: { // aes_keys.txt FileUtil::Delete(FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir) + AES_KEYS); } + case 5: { // Config savegame + FileUtil::DeleteDirRecursively( + fmt::format("{}data/00000000000000000000000000000000/sysdata/00010017/", + FileUtil::GetUserPath(FileUtil::UserPath::NANDDir))); + } default: UNREACHABLE_MSG("Unexpected sysdata id {}", id); } @@ -575,6 +613,7 @@ std::vector LoadPresetConfig(std::string mount_point) { LOAD_DATA(safe_mode_firm_path, "firm/"); LOAD_DATA(seed_db_path, SEED_DB); LOAD_DATA(secret_sector_path, SECRET_SECTOR); + LOAD_DATA(config_savegame_path, "config.sav"); LOAD_DATA(system_archives_path, "sysarchives/"); #undef LOAD_DATA } diff --git a/src/core/importer.h b/src/core/importer.h index 9e5c765..ecc29d9 100644 --- a/src/core/importer.h +++ b/src/core/importer.h @@ -57,9 +57,10 @@ struct Config { std::string safe_mode_firm_path; ///< Path to safe mode firm (A folder) (Sysdata 1) std::string seed_db_path; ///< Path to seeddb.bin (Sysdata 2) std::string secret_sector_path; ///< Path to secret sector (New3DS only) (Sysdata 3) - std::string system_archives_path; ///< Path to system archives. + // Note: Sysdata 4 is aes_keys.txt (slot0x25KeyX) + std::string config_savegame_path; ///< Path to config savegame (Sysdata 5) - // Sysdata 4 is aes_keys.db (slot0x25KeyX) + std::string system_archives_path; ///< Path to system archives. }; class SDMCImporter { diff --git a/src/core/inner_fat.h b/src/core/inner_fat.h index 8e876d0..0a3f666 100644 --- a/src/core/inner_fat.h +++ b/src/core/inner_fat.h @@ -121,12 +121,6 @@ public: */ virtual bool Extract(std::string path) const = 0; -protected: - /** - * Gets the ArchiveFormatInfo of this archive, used for writing the archive metadata. - */ - virtual ArchiveFormatInfo GetFormatInfo() const = 0; - /** * Extracts the index-th file in the file entry table to a certain path. (The path does not * contain the file name). @@ -146,6 +140,12 @@ protected: */ bool WriteMetadata(const std::string& path) const; +protected: + /** + * Gets the ArchiveFormatInfo of this archive, used for writing the archive metadata. + */ + virtual ArchiveFormatInfo GetFormatInfo() const = 0; + bool is_good = false; FATHeader header; FileSystemInformation fs_info;