mirror of
https://git.h3cjp.net/H3cJP/yuzu.git
synced 2024-11-14 20:22:58 +00:00
Avoid parsing RomFS to directory in NCA
This commit is contained in:
parent
826b1394e8
commit
9e88f03e75
|
@ -62,6 +62,13 @@ enum class Language : u8 {
|
||||||
Chinese = 14,
|
Chinese = 14,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static std::array<std::string, 15> LANGUAGE_NAMES = {
|
||||||
|
"AmericanEnglish", "BritishEnglish", "Japanese",
|
||||||
|
"French", "German", "LatinAmericanSpanish",
|
||||||
|
"Spanish", "Italian", "Dutch",
|
||||||
|
"CanadianFrench", "Portugese", "Russian",
|
||||||
|
"Korean", "Taiwanese", "Chinese"};
|
||||||
|
|
||||||
// A class representing the format used by NX metadata files, typically named Control.nacp.
|
// A class representing the format used by NX metadata files, typically named Control.nacp.
|
||||||
// These store application name, dev name, title id, and other miscellaneous data.
|
// These store application name, dev name, title id, and other miscellaneous data.
|
||||||
class NACP {
|
class NACP {
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "common/file_util.h"
|
#include "common/file_util.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/file_sys/content_archive.h"
|
#include "core/file_sys/content_archive.h"
|
||||||
|
#include "core/file_sys/control_metadata.h"
|
||||||
#include "core/gdbstub/gdbstub.h"
|
#include "core/gdbstub/gdbstub.h"
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/hle/kernel/resource_limit.h"
|
#include "core/hle/kernel/resource_limit.h"
|
||||||
|
@ -17,8 +18,50 @@
|
||||||
|
|
||||||
namespace Loader {
|
namespace Loader {
|
||||||
|
|
||||||
AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file)
|
AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file_)
|
||||||
: AppLoader(std::move(file)) {}
|
: AppLoader(std::move(file_)) {
|
||||||
|
const auto dir = file->GetContainingDirectory();
|
||||||
|
|
||||||
|
// Icon
|
||||||
|
FileSys::VirtualFile icon_file = nullptr;
|
||||||
|
for (const auto& language : FileSys::LANGUAGE_NAMES) {
|
||||||
|
icon_file = dir->GetFile("icon_" + language + ".dat");
|
||||||
|
if (icon_file != nullptr) {
|
||||||
|
icon_data = icon_file->ReadAllBytes();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (icon_data.empty()) {
|
||||||
|
// Any png, jpeg, or bmp file
|
||||||
|
const auto& files = dir->GetFiles();
|
||||||
|
const auto icon_iter =
|
||||||
|
std::find_if(files.begin(), files.end(), [](const FileSys::VirtualFile& file) {
|
||||||
|
return file->GetExtension() == "png" || file->GetExtension() == "jpg" ||
|
||||||
|
file->GetExtension() == "bmp" || file->GetExtension() == "jpeg";
|
||||||
|
});
|
||||||
|
if (icon_iter != files.end())
|
||||||
|
icon_data = (*icon_iter)->ReadAllBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Metadata
|
||||||
|
FileSys::VirtualFile nacp_file = dir->GetFile("control.nacp");
|
||||||
|
if (nacp_file == nullptr) {
|
||||||
|
const auto& files = dir->GetFiles();
|
||||||
|
const auto nacp_iter =
|
||||||
|
std::find_if(files.begin(), files.end(), [](const FileSys::VirtualFile& file) {
|
||||||
|
return file->GetExtension() == "nacp";
|
||||||
|
});
|
||||||
|
if (nacp_iter != files.end())
|
||||||
|
nacp_file = *nacp_iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nacp_file != nullptr) {
|
||||||
|
FileSys::NACP nacp(nacp_file);
|
||||||
|
title_id = nacp.GetTitleId();
|
||||||
|
name = nacp.GetApplicationName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(
|
AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(
|
||||||
FileSys::VirtualDir directory)
|
FileSys::VirtualDir directory)
|
||||||
|
@ -105,4 +148,25 @@ ResultStatus AppLoader_DeconstructedRomDirectory::ReadRomFS(FileSys::VirtualFile
|
||||||
return ResultStatus::Success;
|
return ResultStatus::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ResultStatus AppLoader_DeconstructedRomDirectory::ReadIcon(std::vector<u8>& buffer) {
|
||||||
|
if (icon_data.empty())
|
||||||
|
return ResultStatus::ErrorNotUsed;
|
||||||
|
buffer = icon_data;
|
||||||
|
return ResultStatus::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultStatus AppLoader_DeconstructedRomDirectory::ReadProgramId(u64& out_program_id) {
|
||||||
|
if (name.empty())
|
||||||
|
return ResultStatus::ErrorNotUsed;
|
||||||
|
out_program_id = title_id;
|
||||||
|
return ResultStatus::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultStatus AppLoader_DeconstructedRomDirectory::ReadTitle(std::string& title) {
|
||||||
|
if (name.empty())
|
||||||
|
return ResultStatus::ErrorNotUsed;
|
||||||
|
title = name;
|
||||||
|
return ResultStatus::Success;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Loader
|
} // namespace Loader
|
||||||
|
|
|
@ -39,11 +39,18 @@ public:
|
||||||
ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
|
ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
|
||||||
|
|
||||||
ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
|
ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
|
||||||
|
ResultStatus ReadIcon(std::vector<u8>& buffer) override;
|
||||||
|
ResultStatus ReadProgramId(u64& out_program_id) override;
|
||||||
|
ResultStatus ReadTitle(std::string& title) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FileSys::ProgramMetadata metadata;
|
FileSys::ProgramMetadata metadata;
|
||||||
FileSys::VirtualFile romfs;
|
FileSys::VirtualFile romfs;
|
||||||
FileSys::VirtualDir dir;
|
FileSys::VirtualDir dir;
|
||||||
|
|
||||||
|
std::vector<u8> icon_data;
|
||||||
|
std::string name;
|
||||||
|
u64 title_id{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Loader
|
} // namespace Loader
|
||||||
|
|
|
@ -68,7 +68,7 @@ FileType GuessFromFilename(const std::string& name) {
|
||||||
return FileType::Unknown;
|
return FileType::Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* GetFileTypeString(FileType type) {
|
std::string GetFileTypeString(FileType type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case FileType::ELF:
|
case FileType::ELF:
|
||||||
return "ELF";
|
return "ELF";
|
||||||
|
|
|
@ -61,7 +61,7 @@ FileType GuessFromFilename(const std::string& name);
|
||||||
/**
|
/**
|
||||||
* Convert a FileType into a string which can be displayed to the user.
|
* Convert a FileType into a string which can be displayed to the user.
|
||||||
*/
|
*/
|
||||||
const char* GetFileTypeString(FileType type);
|
std::string GetFileTypeString(FileType type);
|
||||||
|
|
||||||
/// Return type for functions in Loader namespace
|
/// Return type for functions in Loader namespace
|
||||||
enum class ResultStatus {
|
enum class ResultStatus {
|
||||||
|
|
|
@ -77,8 +77,8 @@ ResultStatus AppLoader_NCA::ReadRomFS(FileSys::VirtualFile& dir) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultStatus AppLoader_NCA::ReadProgramId(u64& out_program_id) {
|
ResultStatus AppLoader_NCA::ReadProgramId(u64& out_program_id) {
|
||||||
if (nca == nullptr)
|
if (nca == nullptr || nca->GetStatus() != ResultStatus::Success)
|
||||||
return ResultStatus::ErrorNotLoaded;
|
return ResultStatus::ErrorInvalidFormat;
|
||||||
out_program_id = nca->GetTitleId();
|
out_program_id = nca->GetTitleId();
|
||||||
return ResultStatus::Success;
|
return ResultStatus::Success;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@ public:
|
||||||
ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
|
ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
|
||||||
|
|
||||||
ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
|
ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
|
||||||
|
ResultStatus ReadProgramId(u64& out_program_id) override;
|
||||||
|
|
||||||
ResultStatus ReadProgramId(u64& out_program_id) override;
|
ResultStatus ReadProgramId(u64& out_program_id) override;
|
||||||
|
|
||||||
|
@ -41,6 +42,7 @@ public:
|
||||||
private:
|
private:
|
||||||
FileSys::ProgramMetadata metadata;
|
FileSys::ProgramMetadata metadata;
|
||||||
|
|
||||||
|
FileSys::NCAHeader header;
|
||||||
std::unique_ptr<FileSys::NCA> nca;
|
std::unique_ptr<FileSys::NCA> nca;
|
||||||
std::unique_ptr<AppLoader_DeconstructedRomDirectory> directory_loader;
|
std::unique_ptr<AppLoader_DeconstructedRomDirectory> directory_loader;
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,6 +17,8 @@ add_executable(yuzu
|
||||||
configuration/configure_debug.h
|
configuration/configure_debug.h
|
||||||
configuration/configure_dialog.cpp
|
configuration/configure_dialog.cpp
|
||||||
configuration/configure_dialog.h
|
configuration/configure_dialog.h
|
||||||
|
configuration/configure_gamelist.cpp
|
||||||
|
configuration/configure_gamelist.h
|
||||||
configuration/configure_general.cpp
|
configuration/configure_general.cpp
|
||||||
configuration/configure_general.h
|
configuration/configure_general.h
|
||||||
configuration/configure_graphics.cpp
|
configuration/configure_graphics.cpp
|
||||||
|
@ -59,6 +61,7 @@ set(UIS
|
||||||
configuration/configure.ui
|
configuration/configure.ui
|
||||||
configuration/configure_audio.ui
|
configuration/configure_audio.ui
|
||||||
configuration/configure_debug.ui
|
configuration/configure_debug.ui
|
||||||
|
configuration/configure_gamelist.ui
|
||||||
configuration/configure_general.ui
|
configuration/configure_general.ui
|
||||||
configuration/configure_graphics.ui
|
configuration/configure_graphics.ui
|
||||||
configuration/configure_input.ui
|
configuration/configure_input.ui
|
||||||
|
|
|
@ -122,6 +122,13 @@ void Config::ReadValues() {
|
||||||
qt_config->beginGroup("UI");
|
qt_config->beginGroup("UI");
|
||||||
UISettings::values.theme = qt_config->value("theme", UISettings::themes[0].second).toString();
|
UISettings::values.theme = qt_config->value("theme", UISettings::themes[0].second).toString();
|
||||||
|
|
||||||
|
qt_config->beginGroup("UIGameList");
|
||||||
|
UISettings::values.show_unknown = qt_config->value("show_unknown", true).toBool();
|
||||||
|
UISettings::values.icon_size = qt_config->value("icon_size", 48).toUInt();
|
||||||
|
UISettings::values.row_1_text_id = qt_config->value("row_1_text_id", 0).toUInt();
|
||||||
|
UISettings::values.row_2_text_id = qt_config->value("row_2_text_id", 3).toUInt();
|
||||||
|
qt_config->endGroup();
|
||||||
|
|
||||||
qt_config->beginGroup("UILayout");
|
qt_config->beginGroup("UILayout");
|
||||||
UISettings::values.geometry = qt_config->value("geometry").toByteArray();
|
UISettings::values.geometry = qt_config->value("geometry").toByteArray();
|
||||||
UISettings::values.state = qt_config->value("state").toByteArray();
|
UISettings::values.state = qt_config->value("state").toByteArray();
|
||||||
|
@ -234,6 +241,13 @@ void Config::SaveValues() {
|
||||||
qt_config->beginGroup("UI");
|
qt_config->beginGroup("UI");
|
||||||
qt_config->setValue("theme", UISettings::values.theme);
|
qt_config->setValue("theme", UISettings::values.theme);
|
||||||
|
|
||||||
|
qt_config->beginGroup("UIGameList");
|
||||||
|
qt_config->setValue("show_unknown", UISettings::values.show_unknown);
|
||||||
|
qt_config->setValue("icon_size", UISettings::values.icon_size);
|
||||||
|
qt_config->setValue("row_1_text_id", UISettings::values.row_1_text_id);
|
||||||
|
qt_config->setValue("row_2_text_id", UISettings::values.row_2_text_id);
|
||||||
|
qt_config->endGroup();
|
||||||
|
|
||||||
qt_config->beginGroup("UILayout");
|
qt_config->beginGroup("UILayout");
|
||||||
qt_config->setValue("geometry", UISettings::values.geometry);
|
qt_config->setValue("geometry", UISettings::values.geometry);
|
||||||
qt_config->setValue("state", UISettings::values.state);
|
qt_config->setValue("state", UISettings::values.state);
|
||||||
|
|
|
@ -24,6 +24,11 @@
|
||||||
<string>General</string>
|
<string>General</string>
|
||||||
</attribute>
|
</attribute>
|
||||||
</widget>
|
</widget>
|
||||||
|
<widget class="ConfigureGameList" name="gameListTab">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Game List</string>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
<widget class="ConfigureSystem" name="systemTab">
|
<widget class="ConfigureSystem" name="systemTab">
|
||||||
<attribute name="title">
|
<attribute name="title">
|
||||||
<string>System</string>
|
<string>System</string>
|
||||||
|
@ -67,6 +72,12 @@
|
||||||
<header>configuration/configure_general.h</header>
|
<header>configuration/configure_general.h</header>
|
||||||
<container>1</container>
|
<container>1</container>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>ConfigureGameList</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header>configuration/configure_gamelist.h</header>
|
||||||
|
<container>1</container>
|
||||||
|
</customwidget>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
<class>ConfigureSystem</class>
|
<class>ConfigureSystem</class>
|
||||||
<extends>QWidget</extends>
|
<extends>QWidget</extends>
|
||||||
|
|
|
@ -18,6 +18,7 @@ void ConfigureDialog::setConfiguration() {}
|
||||||
|
|
||||||
void ConfigureDialog::applyConfiguration() {
|
void ConfigureDialog::applyConfiguration() {
|
||||||
ui->generalTab->applyConfiguration();
|
ui->generalTab->applyConfiguration();
|
||||||
|
ui->gameListTab->applyConfiguration();
|
||||||
ui->systemTab->applyConfiguration();
|
ui->systemTab->applyConfiguration();
|
||||||
ui->inputTab->applyConfiguration();
|
ui->inputTab->applyConfiguration();
|
||||||
ui->graphicsTab->applyConfiguration();
|
ui->graphicsTab->applyConfiguration();
|
||||||
|
|
61
src/yuzu/configuration/configure_gamelist.cpp
Normal file
61
src/yuzu/configuration/configure_gamelist.cpp
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
// Copyright 2016 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "core/core.h"
|
||||||
|
#include "core/settings.h"
|
||||||
|
#include "ui_configure_gamelist.h"
|
||||||
|
#include "ui_settings.h"
|
||||||
|
#include "yuzu/configuration/configure_gamelist.h"
|
||||||
|
|
||||||
|
ConfigureGameList::ConfigureGameList(QWidget* parent)
|
||||||
|
: QWidget(parent), ui(new Ui::ConfigureGameList) {
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
static std::vector<std::pair<u32, std::string>> default_icon_sizes{
|
||||||
|
std::make_pair(0, "None"), std::make_pair(24, "Small"),
|
||||||
|
std::make_pair(48, "Standard"), std::make_pair(96, "Large"),
|
||||||
|
std::make_pair(256, "Full Size"),
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const auto& size : default_icon_sizes) {
|
||||||
|
ui->icon_size_combobox->addItem(QString::fromStdString(size.second + " (" +
|
||||||
|
std::to_string(size.first) + "x" +
|
||||||
|
std::to_string(size.first) + ")"),
|
||||||
|
size.first);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<std::string> row_text_names{
|
||||||
|
"Filename",
|
||||||
|
"Filetype",
|
||||||
|
"Title ID",
|
||||||
|
"Title Name",
|
||||||
|
};
|
||||||
|
|
||||||
|
for (size_t i = 0; i < row_text_names.size(); ++i) {
|
||||||
|
ui->row_1_text_combobox->addItem(QString::fromStdString(row_text_names[i]), i);
|
||||||
|
ui->row_2_text_combobox->addItem(QString::fromStdString(row_text_names[i]), i);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->setConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigureGameList::~ConfigureGameList() {}
|
||||||
|
|
||||||
|
void ConfigureGameList::setConfiguration() {
|
||||||
|
ui->show_unknown->setChecked(UISettings::values.show_unknown);
|
||||||
|
ui->icon_size_combobox->setCurrentIndex(
|
||||||
|
ui->icon_size_combobox->findData(UISettings::values.icon_size));
|
||||||
|
ui->row_1_text_combobox->setCurrentIndex(
|
||||||
|
ui->row_1_text_combobox->findData(UISettings::values.row_1_text_id));
|
||||||
|
ui->row_2_text_combobox->setCurrentIndex(
|
||||||
|
ui->row_2_text_combobox->findData(UISettings::values.row_2_text_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigureGameList::applyConfiguration() {
|
||||||
|
UISettings::values.show_unknown = ui->show_unknown->isChecked();
|
||||||
|
UISettings::values.icon_size = ui->icon_size_combobox->currentData().toUInt();
|
||||||
|
UISettings::values.row_1_text_id = ui->row_1_text_combobox->currentData().toUInt();
|
||||||
|
UISettings::values.row_2_text_id = ui->row_2_text_combobox->currentData().toUInt();
|
||||||
|
Settings::Apply();
|
||||||
|
}
|
28
src/yuzu/configuration/configure_gamelist.h
Normal file
28
src/yuzu/configuration/configure_gamelist.h
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
// Copyright 2016 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class ConfigureGameList;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ConfigureGameList : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ConfigureGameList(QWidget* parent = nullptr);
|
||||||
|
~ConfigureGameList();
|
||||||
|
|
||||||
|
void applyConfiguration();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setConfiguration();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<Ui::ConfigureGameList> ui;
|
||||||
|
};
|
126
src/yuzu/configuration/configure_gamelist.ui
Normal file
126
src/yuzu/configuration/configure_gamelist.ui
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>ConfigureGameList</class>
|
||||||
|
<widget class="QWidget" name="ConfigureGeneral">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>300</width>
|
||||||
|
<height>377</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="HorizontalLayout">
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="VerticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="GeneralGroupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>General</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="GeneralHorizontalLayout">
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="GeneralVerticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="show_unknown">
|
||||||
|
<property name="text">
|
||||||
|
<string>Show files with type 'Unknown'</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="IconSizeGroupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Icon Size</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="icon_size_qhbox_layout">
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="icon_size_qvbox_layout">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="icon_size_qhbox_layout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="icon_size_label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Icon Size:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="icon_size_combobox"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="RowGroupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Row Text</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="RowHorizontalLayout">
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="RowVerticalLayout">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="row_1_qhbox_layout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="row_1_label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Row 1 Text:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="row_1_text_combobox"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="row_2_qhbox_layout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="row_2_label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Row 2 Text:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="row_2_text_combobox"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
|
@ -12,6 +12,8 @@
|
||||||
#include "common/common_paths.h"
|
#include "common/common_paths.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/string_util.h"
|
#include "common/string_util.h"
|
||||||
|
#include "core/file_sys/content_archive.h"
|
||||||
|
#include "core/file_sys/control_metadata.h"
|
||||||
#include "core/file_sys/vfs_real.h"
|
#include "core/file_sys/vfs_real.h"
|
||||||
#include "core/loader/loader.h"
|
#include "core/loader/loader.h"
|
||||||
#include "game_list.h"
|
#include "game_list.h"
|
||||||
|
@ -398,7 +400,31 @@ void GameList::RefreshGameDirectory() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsigned int recursion) {
|
void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsigned int recursion) {
|
||||||
const auto callback = [this, recursion](u64* num_entries_out, const std::string& directory,
|
boost::container::flat_map<u64, std::shared_ptr<FileSys::NCA>> nca_control_map;
|
||||||
|
|
||||||
|
const auto nca_control_callback =
|
||||||
|
[this, &nca_control_map](u64* num_entries_out, const std::string& directory,
|
||||||
|
const std::string& virtual_name) -> bool {
|
||||||
|
std::string physical_name = directory + DIR_SEP + virtual_name;
|
||||||
|
|
||||||
|
if (stop_processing)
|
||||||
|
return false; // Breaks the callback loop.
|
||||||
|
|
||||||
|
bool is_dir = FileUtil::IsDirectory(physical_name);
|
||||||
|
QFileInfo file_info(physical_name.c_str());
|
||||||
|
if (!is_dir && file_info.suffix().toStdString() == "nca") {
|
||||||
|
auto nca = std::make_shared<FileSys::NCA>(
|
||||||
|
std::make_shared<FileSys::RealVfsFile>(physical_name));
|
||||||
|
if (nca->GetType() == FileSys::NCAContentType::Control)
|
||||||
|
nca_control_map.insert_or_assign(nca->GetTitleId(), nca);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
FileUtil::ForeachDirectoryEntry(nullptr, dir_path, nca_control_callback);
|
||||||
|
|
||||||
|
const auto callback = [this, recursion,
|
||||||
|
&nca_control_map](u64* num_entries_out, const std::string& directory,
|
||||||
const std::string& virtual_name) -> bool {
|
const std::string& virtual_name) -> bool {
|
||||||
std::string physical_name = directory + DIR_SEP + virtual_name;
|
std::string physical_name = directory + DIR_SEP + virtual_name;
|
||||||
|
|
||||||
|
@ -410,17 +436,50 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign
|
||||||
(HasSupportedFileExtension(physical_name) || IsExtractedNCAMain(physical_name))) {
|
(HasSupportedFileExtension(physical_name) || IsExtractedNCAMain(physical_name))) {
|
||||||
std::unique_ptr<Loader::AppLoader> loader =
|
std::unique_ptr<Loader::AppLoader> loader =
|
||||||
Loader::GetLoader(std::make_shared<FileSys::RealVfsFile>(physical_name));
|
Loader::GetLoader(std::make_shared<FileSys::RealVfsFile>(physical_name));
|
||||||
if (!loader)
|
if (!loader || ((loader->GetFileType() == Loader::FileType::Unknown ||
|
||||||
|
loader->GetFileType() == Loader::FileType::Error) &&
|
||||||
|
!UISettings::values.show_unknown))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
std::vector<u8> smdh;
|
std::vector<u8> icon;
|
||||||
loader->ReadIcon(smdh);
|
const auto res1 = loader->ReadIcon(icon);
|
||||||
|
|
||||||
u64 program_id = 0;
|
u64 program_id;
|
||||||
loader->ReadProgramId(program_id);
|
const auto res2 = loader->ReadProgramId(program_id);
|
||||||
|
|
||||||
|
std::string name = " ";
|
||||||
|
const auto res3 = loader->ReadTitle(name);
|
||||||
|
|
||||||
|
if ((res1 == Loader::ResultStatus::ErrorNotUsed ||
|
||||||
|
res1 == Loader::ResultStatus::ErrorNotImplemented) &&
|
||||||
|
(res3 == Loader::ResultStatus::ErrorNotUsed ||
|
||||||
|
res3 == Loader::ResultStatus::ErrorNotImplemented) &&
|
||||||
|
res2 == Loader::ResultStatus::Success) {
|
||||||
|
// Use from metadata pool.
|
||||||
|
if (nca_control_map.find(program_id) != nca_control_map.end()) {
|
||||||
|
const auto nca = nca_control_map[program_id];
|
||||||
|
auto control_dir = nca->GetSection(0);
|
||||||
|
|
||||||
|
auto nacp_file = control_dir->GetFile("control.nacp");
|
||||||
|
FileSys::NACP nacp(nacp_file);
|
||||||
|
name = nacp.GetApplicationName();
|
||||||
|
|
||||||
|
FileSys::VirtualFile icon_file = nullptr;
|
||||||
|
for (const auto& language : FileSys::LANGUAGE_NAMES) {
|
||||||
|
icon_file = control_dir->GetFile("icon_" + language + ".dat");
|
||||||
|
if (icon_file != nullptr) {
|
||||||
|
icon = icon_file->ReadAllBytes();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
emit EntryReady({
|
emit EntryReady({
|
||||||
new GameListItemPath(FormatGameName(physical_name), smdh, program_id),
|
new GameListItemPath(
|
||||||
|
FormatGameName(physical_name), icon, QString::fromStdString(name),
|
||||||
|
QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType())),
|
||||||
|
program_id),
|
||||||
new GameListItem(
|
new GameListItem(
|
||||||
QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))),
|
QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))),
|
||||||
new GameListItemSize(FileUtil::GetSize(physical_name)),
|
new GameListItemSize(FileUtil::GetSize(physical_name)),
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <QStandardItem>
|
#include <QStandardItem>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include "common/string_util.h"
|
#include "common/string_util.h"
|
||||||
|
#include "ui_settings.h"
|
||||||
#include "yuzu/util/util.h"
|
#include "yuzu/util/util.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -18,8 +19,7 @@
|
||||||
* @param large If true, returns large icon (48x48), otherwise returns small icon (24x24)
|
* @param large If true, returns large icon (48x48), otherwise returns small icon (24x24)
|
||||||
* @return QPixmap default icon
|
* @return QPixmap default icon
|
||||||
*/
|
*/
|
||||||
static QPixmap GetDefaultIcon(bool large) {
|
static QPixmap GetDefaultIcon(u32 size) {
|
||||||
int size = large ? 48 : 24;
|
|
||||||
QPixmap icon(size, size);
|
QPixmap icon(size, size);
|
||||||
icon.fill(Qt::transparent);
|
icon.fill(Qt::transparent);
|
||||||
return icon;
|
return icon;
|
||||||
|
@ -44,11 +44,25 @@ public:
|
||||||
static const int FullPathRole = Qt::UserRole + 1;
|
static const int FullPathRole = Qt::UserRole + 1;
|
||||||
static const int TitleRole = Qt::UserRole + 2;
|
static const int TitleRole = Qt::UserRole + 2;
|
||||||
static const int ProgramIdRole = Qt::UserRole + 3;
|
static const int ProgramIdRole = Qt::UserRole + 3;
|
||||||
|
static const int FileTypeRole = Qt::UserRole + 4;
|
||||||
|
|
||||||
GameListItemPath() = default;
|
GameListItemPath() = default;
|
||||||
GameListItemPath(const QString& game_path, const std::vector<u8>& smdh_data, u64 program_id) {
|
GameListItemPath(const QString& game_path, const std::vector<u8>& picture_data,
|
||||||
|
const QString& game_name, const QString& game_type, u64 program_id)
|
||||||
|
: GameListItem() {
|
||||||
setData(game_path, FullPathRole);
|
setData(game_path, FullPathRole);
|
||||||
|
setData(game_name, TitleRole);
|
||||||
setData(qulonglong(program_id), ProgramIdRole);
|
setData(qulonglong(program_id), ProgramIdRole);
|
||||||
|
setData(game_type, FileTypeRole);
|
||||||
|
|
||||||
|
QPixmap picture;
|
||||||
|
u32 size = UISettings::values.icon_size;
|
||||||
|
if (!picture.loadFromData(picture_data.data(), picture_data.size()))
|
||||||
|
picture = GetDefaultIcon(size);
|
||||||
|
|
||||||
|
picture = picture.scaled(size, size);
|
||||||
|
|
||||||
|
setData(picture, Qt::DecorationRole);
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant data(int role) const override {
|
QVariant data(int role) const override {
|
||||||
|
@ -57,7 +71,23 @@ public:
|
||||||
Common::SplitPath(data(FullPathRole).toString().toStdString(), nullptr, &filename,
|
Common::SplitPath(data(FullPathRole).toString().toStdString(), nullptr, &filename,
|
||||||
nullptr);
|
nullptr);
|
||||||
QString title = data(TitleRole).toString();
|
QString title = data(TitleRole).toString();
|
||||||
return QString::fromStdString(filename) + (title.isEmpty() ? "" : "\n " + title);
|
|
||||||
|
std::vector<QString> row_data{
|
||||||
|
QString::fromStdString(filename),
|
||||||
|
data(FileTypeRole).toString(),
|
||||||
|
QString::fromStdString(fmt::format("0x{:016X}", data(ProgramIdRole).toULongLong())),
|
||||||
|
data(TitleRole).toString(),
|
||||||
|
};
|
||||||
|
|
||||||
|
auto row1 = row_data.at(UISettings::values.row_1_text_id);
|
||||||
|
auto row2 = row_data.at(UISettings::values.row_2_text_id);
|
||||||
|
|
||||||
|
if (row1.isEmpty() || row1 == row2)
|
||||||
|
return row2;
|
||||||
|
if (row2.isEmpty())
|
||||||
|
return row1;
|
||||||
|
|
||||||
|
return row1 + "\n " + row2;
|
||||||
} else {
|
} else {
|
||||||
return GameListItem::data(role);
|
return GameListItem::data(role);
|
||||||
}
|
}
|
||||||
|
|
|
@ -764,6 +764,7 @@ void GMainWindow::OnConfigure() {
|
||||||
configureDialog.applyConfiguration();
|
configureDialog.applyConfiguration();
|
||||||
if (UISettings::values.theme != old_theme)
|
if (UISettings::values.theme != old_theme)
|
||||||
UpdateUITheme();
|
UpdateUITheme();
|
||||||
|
game_list->PopulateAsync(UISettings::values.gamedir, UISettings::values.gamedir_deepscan);
|
||||||
config->Save();
|
config->Save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,12 @@ struct Values {
|
||||||
|
|
||||||
// logging
|
// logging
|
||||||
bool show_console;
|
bool show_console;
|
||||||
|
|
||||||
|
// Game List
|
||||||
|
bool show_unknown;
|
||||||
|
uint32_t icon_size;
|
||||||
|
uint8_t row_1_text_id;
|
||||||
|
uint8_t row_2_text_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Values values;
|
extern Values values;
|
||||||
|
|
Loading…
Reference in a new issue