|
|
|
@ -9,6 +9,7 @@
|
|
|
|
|
|
|
|
|
|
#include <QDir>
|
|
|
|
|
#include <QFileInfo>
|
|
|
|
|
#include <QSettings>
|
|
|
|
|
|
|
|
|
|
#include "common/common_paths.h"
|
|
|
|
|
#include "common/file_util.h"
|
|
|
|
@ -30,13 +31,101 @@
|
|
|
|
|
#include "yuzu/ui_settings.h"
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
T GetGameListCachedObject(const std::string& filename, const std::string& ext,
|
|
|
|
|
const std::function<T()>& generator);
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
|
QString GetGameListCachedObject(const std::string& filename, const std::string& ext,
|
|
|
|
|
const std::function<QString()>& generator) {
|
|
|
|
|
if (!UISettings::values.cache_game_list || filename == "0000000000000000")
|
|
|
|
|
return generator();
|
|
|
|
|
|
|
|
|
|
const auto& path = FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + DIR_SEP + "game_list" +
|
|
|
|
|
DIR_SEP + filename + "." + ext;
|
|
|
|
|
|
|
|
|
|
FileUtil::CreateFullPath(path);
|
|
|
|
|
|
|
|
|
|
if (!FileUtil::Exists(path)) {
|
|
|
|
|
const auto str = generator();
|
|
|
|
|
|
|
|
|
|
std::ofstream stream(path);
|
|
|
|
|
if (stream)
|
|
|
|
|
stream << str.toStdString();
|
|
|
|
|
|
|
|
|
|
stream.close();
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::ifstream stream(path);
|
|
|
|
|
|
|
|
|
|
if (stream) {
|
|
|
|
|
const std::string out(std::istreambuf_iterator<char>{stream},
|
|
|
|
|
std::istreambuf_iterator<char>{});
|
|
|
|
|
stream.close();
|
|
|
|
|
return QString::fromStdString(out);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return generator();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
|
std::pair<std::vector<u8>, std::string> GetGameListCachedObject(
|
|
|
|
|
const std::string& filename, const std::string& ext,
|
|
|
|
|
const std::function<std::pair<std::vector<u8>, std::string>()>& generator) {
|
|
|
|
|
if (!UISettings::values.cache_game_list || filename == "0000000000000000")
|
|
|
|
|
return generator();
|
|
|
|
|
|
|
|
|
|
const auto& path1 = FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + DIR_SEP +
|
|
|
|
|
"game_list" + DIR_SEP + filename + ".jpeg";
|
|
|
|
|
const auto& path2 = FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + DIR_SEP +
|
|
|
|
|
"game_list" + DIR_SEP + filename + ".appname.txt";
|
|
|
|
|
|
|
|
|
|
FileUtil::CreateFullPath(path1);
|
|
|
|
|
|
|
|
|
|
if (!FileUtil::Exists(path1) || !FileUtil::Exists(path2)) {
|
|
|
|
|
const auto [icon, nacp] = generator();
|
|
|
|
|
|
|
|
|
|
FileUtil::IOFile file1(path1, "wb");
|
|
|
|
|
file1.Resize(icon.size());
|
|
|
|
|
file1.WriteBytes(icon.data(), icon.size());
|
|
|
|
|
|
|
|
|
|
std::ofstream stream2(path2, std::ios::out);
|
|
|
|
|
if (stream2)
|
|
|
|
|
stream2 << nacp;
|
|
|
|
|
|
|
|
|
|
file1.Close();
|
|
|
|
|
stream2.close();
|
|
|
|
|
return std::make_pair(icon, nacp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FileUtil::IOFile file1(path1, "rb");
|
|
|
|
|
std::ifstream stream2(path2);
|
|
|
|
|
|
|
|
|
|
std::vector<u8> vec(file1.GetSize());
|
|
|
|
|
file1.ReadBytes(vec.data(), vec.size());
|
|
|
|
|
|
|
|
|
|
if (stream2 && !vec.empty()) {
|
|
|
|
|
const std::string out(std::istreambuf_iterator<char>{stream2},
|
|
|
|
|
std::istreambuf_iterator<char>{});
|
|
|
|
|
stream2.close();
|
|
|
|
|
return std::make_pair(vec, out);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return generator();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GetMetadataFromControlNCA(const FileSys::PatchManager& patch_manager, const FileSys::NCA& nca,
|
|
|
|
|
std::vector<u8>& icon, std::string& name) {
|
|
|
|
|
auto [nacp, icon_file] = patch_manager.ParseControlNCA(nca);
|
|
|
|
|
if (icon_file != nullptr)
|
|
|
|
|
icon = icon_file->ReadAllBytes();
|
|
|
|
|
if (nacp != nullptr)
|
|
|
|
|
name = nacp->GetApplicationName();
|
|
|
|
|
auto res = GetGameListCachedObject<std::pair<std::vector<u8>, std::string>>(
|
|
|
|
|
fmt::format("{:016X}", patch_manager.GetTitleID()), {}, [&patch_manager, &nca] {
|
|
|
|
|
const auto [nacp, icon_f] = patch_manager.ParseControlNCA(nca);
|
|
|
|
|
return std::make_pair(icon_f->ReadAllBytes(), nacp->GetApplicationName());
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
icon = std::move(res.first);
|
|
|
|
|
name = std::move(res.second);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool HasSupportedFileExtension(const std::string& file_name) {
|
|
|
|
@ -114,8 +203,11 @@ QList<QStandardItem*> MakeGameListEntry(const std::string& path, const std::stri
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (UISettings::values.show_add_ons) {
|
|
|
|
|
list.insert(
|
|
|
|
|
2, new GameListItem(FormatPatchNameVersions(patch, loader, loader.IsRomFSUpdatable())));
|
|
|
|
|
const auto patch_versions = GetGameListCachedObject<QString>(
|
|
|
|
|
fmt::format("{:016X}", patch.GetTitleID()), "pv.txt", [&patch, &loader] {
|
|
|
|
|
return FormatPatchNameVersions(patch, loader, loader.IsRomFSUpdatable());
|
|
|
|
|
});
|
|
|
|
|
list.insert(2, new GameListItem(patch_versions));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return list;
|
|
|
|
|