[core/filesystem] "easier" cheats folder structure like Ryujinx (#2795)
Less annoying way to make cheats Signed-off-by: lizzie <lizzie@eden-emu.dev> Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2795 Co-authored-by: lizzie <lizzie@eden-emu.dev> Co-committed-by: lizzie <lizzie@eden-emu.dev>
This commit is contained in:
parent
86432f9552
commit
6ff043c4fb
3 changed files with 65 additions and 18 deletions
|
|
@ -9,3 +9,4 @@ This handbook is primarily aimed at the end-user - baking useful knowledge for e
|
||||||
- **[Graphics](user/Graphics.md)**
|
- **[Graphics](user/Graphics.md)**
|
||||||
- **[Platforms and Architectures](user/Architectures.md)**
|
- **[Platforms and Architectures](user/Architectures.md)**
|
||||||
- **[Testing](user/Testing.md)**
|
- **[Testing](user/Testing.md)**
|
||||||
|
- **[Data, savefiles and storage](user/Storage.md)**
|
||||||
|
|
|
||||||
39
docs/user/Storage.md
Normal file
39
docs/user/Storage.md
Normal file
|
|
@ -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/*`.
|
||||||
|
|
@ -316,8 +316,7 @@ bool PatchManager::HasNSOPatch(const BuildID& build_id_, std::string_view name)
|
||||||
return !CollectPatches(patch_dirs, build_id).empty();
|
return !CollectPatches(patch_dirs, build_id).empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList(
|
std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList(const BuildID& build_id_) const {
|
||||||
const BuildID& build_id_) const {
|
|
||||||
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
|
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
|
||||||
if (load_dir == nullptr) {
|
if (load_dir == nullptr) {
|
||||||
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
|
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];
|
const auto& disabled = Settings::values.disabled_addons[title_id];
|
||||||
auto patch_dirs = load_dir->GetSubdirectories();
|
auto patch_dirs = load_dir->GetSubdirectories();
|
||||||
std::sort(patch_dirs.begin(), patch_dirs.end(),
|
std::sort(patch_dirs.begin(), patch_dirs.end(), [](auto const& l, auto const& r) { return l->GetName() < r->GetName(); });
|
||||||
[](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
|
|
||||||
|
|
||||||
|
// <mod dir> / <folder> / cheats / <build id>.txt
|
||||||
std::vector<Core::Memory::CheatEntry> out;
|
std::vector<Core::Memory::CheatEntry> out;
|
||||||
for (const auto& subdir : patch_dirs) {
|
for (const auto& subdir : patch_dirs) {
|
||||||
if (std::find(disabled.cbegin(), disabled.cend(), subdir->GetName()) != disabled.cend()) {
|
if (std::find(disabled.cbegin(), disabled.cend(), subdir->GetName()) == disabled.cend()) {
|
||||||
continue;
|
if (auto cheats_dir = FindSubdirectoryCaseless(subdir, "cheats"); cheats_dir != nullptr) {
|
||||||
}
|
if (auto const res = ReadCheatFileFromFolder(title_id, build_id_, cheats_dir, true))
|
||||||
|
|
||||||
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));
|
std::copy(res->begin(), res->end(), std::back_inserter(out));
|
||||||
continue;
|
if (auto const res = ReadCheatFileFromFolder(title_id, build_id_, cheats_dir, false))
|
||||||
}
|
|
||||||
|
|
||||||
if (const auto res = ReadCheatFileFromFolder(title_id, build_id_, cheats_dir, false)) {
|
|
||||||
std::copy(res->begin(), res->end(), std::back_inserter(out));
|
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;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue