aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/User.md1
-rw-r--r--docs/user/Storage.md39
-rw-r--r--src/core/file_sys/patch_manager.cpp41
3 files changed, 64 insertions, 17 deletions
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<Core::Memory::CheatEntry> PatchManager::CreateCheatList(
- const BuildID& build_id_) const {
+std::vector<Core::Memory::CheatEntry> 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<Core::Memory::CheatEntry> 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(); });
+ // <mod dir> / <folder> / cheats / <build id>.txt
std::vector<Core::Memory::CheatEntry> 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 (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));
}
-
- if (const auto 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_')
+ // <mod dir> / <cheat file>.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<u8> 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<const char*>(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;
}