diff --git a/docs/User.md b/docs/User.md index 18f8729aae..7928a90615 100644 --- a/docs/User.md +++ b/docs/User.md @@ -9,3 +9,4 @@ This handbook is primarily aimed at the end-user - baking useful knowledge for e - **[Graphics](user/Graphics.md)** - **[Platforms and Architectures](user/Architectures.md)** - **[Testing](user/Testing.md)** +- **[Data, savefiles and storage](user/Storage.md)** diff --git a/docs/user/Storage.md b/docs/user/Storage.md new file mode 100644 index 0000000000..1719bd967c --- /dev/null +++ b/docs/user/Storage.md @@ -0,0 +1,39 @@ +# User Handbook - Data, savefiles and storage + +## Cheats + +Cheats can be placed in the two manners: + +**Method 1**: +- Right click on "Open mod directory" +- Create a file called `cheat_mycheat.txt` (the file must start with `cheat_` to be recognized as one) +- Write the cheat into said text file +- Done + +This method doesn't account for build IDs, so any cheats for previous builds will not be automatically filtered out. + +**Method 2**: +- Right click on "Open mod directory" +- Create a folder called `My cheat` +- Inside said folder create another one: `cheats` +- Then inside said folder create a file with the build ID in hexadecimal, lowercase, for example `1234FBCDE0000000.txt` +- Write the cheat into said text file +- Done + +To delete a cheat simply do the process backwards (delete the folder/file). + +## Savefiles + +The method to access save data is simple: +- Right click on "Open save directory" + +## Maintaining a library + +### ZFS + +One of the best ways to keep a gallery of archives is using a ZFS pool compressed with zstd. +```sh +sudo zfs create zroot/switch` +sudo zfs set compression=zstd zroot/switch +``` +A new ZFS dataset will then be available on `/zroot/switch`. From which then can be added as a normal game directory. Remember to ensure proper permissions with `chmod 755 /zroot/switch/*`. diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp index 11984ca7ca..a28fdf9056 100644 --- a/src/core/file_sys/patch_manager.cpp +++ b/src/core/file_sys/patch_manager.cpp @@ -316,8 +316,7 @@ bool PatchManager::HasNSOPatch(const BuildID& build_id_, std::string_view name) return !CollectPatches(patch_dirs, build_id).empty(); } -std::vector PatchManager::CreateCheatList( - const BuildID& build_id_) const { +std::vector PatchManager::CreateCheatList(const BuildID& build_id_) const { const auto load_dir = fs_controller.GetModificationLoadRoot(title_id); if (load_dir == nullptr) { LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id); @@ -326,28 +325,36 @@ std::vector PatchManager::CreateCheatList( const auto& disabled = Settings::values.disabled_addons[title_id]; auto patch_dirs = load_dir->GetSubdirectories(); - std::sort(patch_dirs.begin(), patch_dirs.end(), - [](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); }); + std::sort(patch_dirs.begin(), patch_dirs.end(), [](auto const& l, auto const& r) { return l->GetName() < r->GetName(); }); + // / / cheats / .txt std::vector out; for (const auto& subdir : patch_dirs) { - if (std::find(disabled.cbegin(), disabled.cend(), subdir->GetName()) != disabled.cend()) { - continue; - } - - auto cheats_dir = FindSubdirectoryCaseless(subdir, "cheats"); - if (cheats_dir != nullptr) { - if (const auto res = ReadCheatFileFromFolder(title_id, build_id_, cheats_dir, true)) { - std::copy(res->begin(), res->end(), std::back_inserter(out)); - continue; - } - - if (const auto res = ReadCheatFileFromFolder(title_id, build_id_, cheats_dir, false)) { - std::copy(res->begin(), res->end(), std::back_inserter(out)); + if (std::find(disabled.cbegin(), disabled.cend(), subdir->GetName()) == disabled.cend()) { + if (auto cheats_dir = FindSubdirectoryCaseless(subdir, "cheats"); cheats_dir != nullptr) { + if (auto const res = ReadCheatFileFromFolder(title_id, build_id_, cheats_dir, true)) + std::copy(res->begin(), res->end(), std::back_inserter(out)); + if (auto const res = ReadCheatFileFromFolder(title_id, build_id_, cheats_dir, false)) + std::copy(res->begin(), res->end(), std::back_inserter(out)); + } + } + } + // Uncareless user-friendly loading of patches (must start with 'cheat_') + // / .txt + auto const patch_files = load_dir->GetFiles(); + for (auto const& f : patch_files) { + auto const name = f->GetName(); + if (name.starts_with("cheat_") && std::find(disabled.cbegin(), disabled.cend(), name) == disabled.cend()) { + std::vector data(f->GetSize()); + if (f->Read(data.data(), data.size()) == data.size()) { + const Core::Memory::TextCheatParser parser; + auto const res = parser.Parse(std::string_view(reinterpret_cast(data.data()), data.size())); + std::copy(res.begin(), res.end(), std::back_inserter(out)); + } else { + LOG_INFO(Common_Filesystem, "Failed to read cheats file for title_id={:016X}", title_id); } } } - return out; }