|
|
|
@ -7,6 +7,7 @@ |
|
|
|
#include <cstddef>
|
|
|
|
#include <cstring>
|
|
|
|
|
|
|
|
#include "common/file_util.h"
|
|
|
|
#include "common/hex_util.h"
|
|
|
|
#include "common/logging/log.h"
|
|
|
|
#include "core/file_sys/content_archive.h"
|
|
|
|
@ -232,6 +233,57 @@ bool PatchManager::HasNSOPatch(const std::array<u8, 32>& build_id_) const { |
|
|
|
return !CollectPatches(patch_dirs, build_id).empty(); |
|
|
|
} |
|
|
|
|
|
|
|
static std::optional<CheatList> ReadCheatFileFromFolder(u64 title_id, |
|
|
|
const std::array<u8, 0x20>& build_id_, |
|
|
|
const VirtualDir& base_path, bool upper) { |
|
|
|
const auto build_id_raw = Common::HexArrayToString(build_id_, upper); |
|
|
|
const auto build_id = build_id_raw.substr(0, sizeof(u64) * 2); |
|
|
|
const auto file = base_path->GetFile(fmt::format("{}.txt", build_id)); |
|
|
|
|
|
|
|
if (file == nullptr) { |
|
|
|
LOG_INFO(Common_Filesystem, "No cheats file found for title_id={:016X}, build_id={}", |
|
|
|
title_id, build_id); |
|
|
|
return std::nullopt; |
|
|
|
} |
|
|
|
|
|
|
|
std::vector<u8> data(file->GetSize()); |
|
|
|
if (file->Read(data.data(), data.size()) != data.size()) { |
|
|
|
LOG_INFO(Common_Filesystem, "Failed to read cheats file for title_id={:016X}, build_id={}", |
|
|
|
title_id, build_id); |
|
|
|
return std::nullopt; |
|
|
|
} |
|
|
|
|
|
|
|
TextCheatParser parser; |
|
|
|
return parser.Parse(data); |
|
|
|
} |
|
|
|
|
|
|
|
std::vector<CheatList> PatchManager::CreateCheatList(const std::array<u8, 32>& build_id_) const { |
|
|
|
std::vector<CheatList> out; |
|
|
|
|
|
|
|
const auto load_dir = Service::FileSystem::GetModificationLoadRoot(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(); }); |
|
|
|
|
|
|
|
out.reserve(patch_dirs.size()); |
|
|
|
for (const auto& subdir : patch_dirs) { |
|
|
|
auto cheats_dir = subdir->GetSubdirectory("cheats"); |
|
|
|
if (cheats_dir != nullptr) { |
|
|
|
auto res = ReadCheatFileFromFolder(title_id, build_id_, cheats_dir, true); |
|
|
|
if (res.has_value()) { |
|
|
|
out.push_back(std::move(*res)); |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
res = ReadCheatFileFromFolder(title_id, build_id_, cheats_dir, false); |
|
|
|
if (res.has_value()) |
|
|
|
out.push_back(std::move(*res)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return out; |
|
|
|
} |
|
|
|
|
|
|
|
static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type) { |
|
|
|
const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id); |
|
|
|
if ((type != ContentRecordType::Program && type != ContentRecordType::Data) || |
|
|
|
|