diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/file_sys/registered_cache.cpp | 4 | ||||
| -rw-r--r-- | src/core/file_sys/registered_cache.h | 1 | ||||
| -rw-r--r-- | src/yuzu/main.cpp | 73 | ||||
| -rw-r--r-- | src/yuzu/main.h | 6 |
4 files changed, 73 insertions, 11 deletions
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp index d1dea5e82..29b100414 100644 --- a/src/core/file_sys/registered_cache.cpp +++ b/src/core/file_sys/registered_cache.cpp | |||
| @@ -35,6 +35,10 @@ bool operator==(const RegisteredCacheEntry& lhs, const RegisteredCacheEntry& rhs | |||
| 35 | return std::tie(lhs.title_id, lhs.type) == std::tie(rhs.title_id, rhs.type); | 35 | return std::tie(lhs.title_id, lhs.type) == std::tie(rhs.title_id, rhs.type); |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | bool operator!=(const RegisteredCacheEntry& lhs, const RegisteredCacheEntry& rhs) { | ||
| 39 | return !operator==(lhs, rhs); | ||
| 40 | } | ||
| 41 | |||
| 38 | static bool FollowsTwoDigitDirFormat(std::string_view name) { | 42 | static bool FollowsTwoDigitDirFormat(std::string_view name) { |
| 39 | static const std::regex two_digit_regex("000000[0-9A-F]{2}", std::regex_constants::ECMAScript | | 43 | static const std::regex two_digit_regex("000000[0-9A-F]{2}", std::regex_constants::ECMAScript | |
| 40 | std::regex_constants::icase); | 44 | std::regex_constants::icase); |
diff --git a/src/core/file_sys/registered_cache.h b/src/core/file_sys/registered_cache.h index aeb1c69ba..5beceffb3 100644 --- a/src/core/file_sys/registered_cache.h +++ b/src/core/file_sys/registered_cache.h | |||
| @@ -52,6 +52,7 @@ bool operator<(const RegisteredCacheEntry& lhs, const RegisteredCacheEntry& rhs) | |||
| 52 | 52 | ||
| 53 | // std unique requires operator== to identify duplicates. | 53 | // std unique requires operator== to identify duplicates. |
| 54 | bool operator==(const RegisteredCacheEntry& lhs, const RegisteredCacheEntry& rhs); | 54 | bool operator==(const RegisteredCacheEntry& lhs, const RegisteredCacheEntry& rhs); |
| 55 | bool operator!=(const RegisteredCacheEntry& lhs, const RegisteredCacheEntry& rhs); | ||
| 55 | 56 | ||
| 56 | /* | 57 | /* |
| 57 | * A class that catalogues NCAs in the registered directory structure. | 58 | * A class that catalogues NCAs in the registered directory structure. |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index bef9df00d..36c702195 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -100,6 +100,8 @@ __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; | |||
| 100 | } | 100 | } |
| 101 | #endif | 101 | #endif |
| 102 | 102 | ||
| 103 | constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000; | ||
| 104 | |||
| 103 | /** | 105 | /** |
| 104 | * "Callouts" are one-time instructional messages shown to the user. In the config settings, there | 106 | * "Callouts" are one-time instructional messages shown to the user. In the config settings, there |
| 105 | * is a bitfield "callout_flags" options, used to track if a message has already been shown to the | 107 | * is a bitfield "callout_flags" options, used to track if a message has already been shown to the |
| @@ -823,14 +825,10 @@ static bool RomFSRawCopy(QProgressDialog& dialog, const FileSys::VirtualDir& src | |||
| 823 | } | 825 | } |
| 824 | 826 | ||
| 825 | void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_path) { | 827 | void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_path) { |
| 826 | const auto path = fmt::format("{}{:016X}/romfs", | 828 | const auto failed = [this] { |
| 827 | FileUtil::GetUserPath(FileUtil::UserPath::DumpDir), program_id); | ||
| 828 | |||
| 829 | const auto failed = [this, &path] { | ||
| 830 | QMessageBox::warning(this, tr("RomFS Extraction Failed!"), | 829 | QMessageBox::warning(this, tr("RomFS Extraction Failed!"), |
| 831 | tr("There was an error copying the RomFS files or the user " | 830 | tr("There was an error copying the RomFS files or the user " |
| 832 | "cancelled the operation.")); | 831 | "cancelled the operation.")); |
| 833 | vfs->DeleteDirectory(path); | ||
| 834 | }; | 832 | }; |
| 835 | 833 | ||
| 836 | const auto loader = Loader::GetLoader(vfs->OpenFile(game_path, FileSys::Mode::Read)); | 834 | const auto loader = Loader::GetLoader(vfs->OpenFile(game_path, FileSys::Mode::Read)); |
| @@ -845,10 +843,24 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa | |||
| 845 | return; | 843 | return; |
| 846 | } | 844 | } |
| 847 | 845 | ||
| 848 | const auto romfs = | 846 | const auto installed = Service::FileSystem::GetUnionContents(); |
| 849 | loader->IsRomFSUpdatable() | 847 | auto romfs_title_id = SelectRomFSDumpTarget(*installed, program_id); |
| 850 | ? FileSys::PatchManager(program_id).PatchRomFS(file, loader->ReadRomFSIVFCOffset()) | 848 | |
| 851 | : file; | 849 | if (!romfs_title_id) { |
| 850 | failed(); | ||
| 851 | return; | ||
| 852 | } | ||
| 853 | |||
| 854 | const auto path = fmt::format( | ||
| 855 | "{}{:016X}/romfs", FileUtil::GetUserPath(FileUtil::UserPath::DumpDir), *romfs_title_id); | ||
| 856 | |||
| 857 | FileSys::VirtualFile romfs; | ||
| 858 | |||
| 859 | if (*romfs_title_id == program_id) { | ||
| 860 | romfs = file; | ||
| 861 | } else { | ||
| 862 | romfs = installed->GetEntry(*romfs_title_id, FileSys::ContentRecordType::Data)->GetRomFS(); | ||
| 863 | } | ||
| 852 | 864 | ||
| 853 | const auto extracted = FileSys::ExtractRomFS(romfs, FileSys::RomFSExtractionType::Full); | 865 | const auto extracted = FileSys::ExtractRomFS(romfs, FileSys::RomFSExtractionType::Full); |
| 854 | if (extracted == nullptr) { | 866 | if (extracted == nullptr) { |
| @@ -860,6 +872,7 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa | |||
| 860 | 872 | ||
| 861 | if (out == nullptr) { | 873 | if (out == nullptr) { |
| 862 | failed(); | 874 | failed(); |
| 875 | vfs->DeleteDirectory(path); | ||
| 863 | return; | 876 | return; |
| 864 | } | 877 | } |
| 865 | 878 | ||
| @@ -870,8 +883,11 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa | |||
| 870 | "files into the new directory while <br>skeleton will only create the directory " | 883 | "files into the new directory while <br>skeleton will only create the directory " |
| 871 | "structure."), | 884 | "structure."), |
| 872 | {"Full", "Skeleton"}, 0, false, &ok); | 885 | {"Full", "Skeleton"}, 0, false, &ok); |
| 873 | if (!ok) | 886 | if (!ok) { |
| 874 | failed(); | 887 | failed(); |
| 888 | vfs->DeleteDirectory(path); | ||
| 889 | return; | ||
| 890 | } | ||
| 875 | 891 | ||
| 876 | const auto full = res == "Full"; | 892 | const auto full = res == "Full"; |
| 877 | const auto entry_size = CalculateRomFSEntrySize(extracted, full); | 893 | const auto entry_size = CalculateRomFSEntrySize(extracted, full); |
| @@ -888,6 +904,7 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa | |||
| 888 | } else { | 904 | } else { |
| 889 | progress.close(); | 905 | progress.close(); |
| 890 | failed(); | 906 | failed(); |
| 907 | vfs->DeleteDirectory(path); | ||
| 891 | } | 908 | } |
| 892 | } | 909 | } |
| 893 | 910 | ||
| @@ -1459,6 +1476,42 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) { | |||
| 1459 | } | 1476 | } |
| 1460 | } | 1477 | } |
| 1461 | 1478 | ||
| 1479 | boost::optional<u64> GMainWindow::SelectRomFSDumpTarget( | ||
| 1480 | const FileSys::RegisteredCacheUnion& installed, u64 program_id) { | ||
| 1481 | const auto dlc_entries = | ||
| 1482 | installed.ListEntriesFilter(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data); | ||
| 1483 | std::vector<FileSys::RegisteredCacheEntry> dlc_match; | ||
| 1484 | dlc_match.reserve(dlc_entries.size()); | ||
| 1485 | std::copy_if(dlc_entries.begin(), dlc_entries.end(), std::back_inserter(dlc_match), | ||
| 1486 | [&program_id, &installed](const FileSys::RegisteredCacheEntry& entry) { | ||
| 1487 | return (entry.title_id & DLC_BASE_TITLE_ID_MASK) == program_id && | ||
| 1488 | installed.GetEntry(entry)->GetStatus() == Loader::ResultStatus::Success; | ||
| 1489 | }); | ||
| 1490 | |||
| 1491 | std::vector<u64> romfs_tids; | ||
| 1492 | romfs_tids.push_back(program_id); | ||
| 1493 | for (const auto& entry : dlc_match) | ||
| 1494 | romfs_tids.push_back(entry.title_id); | ||
| 1495 | |||
| 1496 | if (romfs_tids.size() > 1) { | ||
| 1497 | QStringList list{"Base"}; | ||
| 1498 | for (std::size_t i = 1; i < romfs_tids.size(); ++i) | ||
| 1499 | list.push_back(QStringLiteral("DLC %1").arg(romfs_tids[i] & 0x7FF)); | ||
| 1500 | |||
| 1501 | bool ok; | ||
| 1502 | const auto res = QInputDialog::getItem( | ||
| 1503 | this, tr("Select RomFS Dump Target"), | ||
| 1504 | tr("Please select which RomFS you would like to dump."), list, 0, false, &ok); | ||
| 1505 | if (!ok) { | ||
| 1506 | return boost::none; | ||
| 1507 | } | ||
| 1508 | |||
| 1509 | return romfs_tids[list.indexOf(res)]; | ||
| 1510 | } | ||
| 1511 | |||
| 1512 | return program_id; | ||
| 1513 | } | ||
| 1514 | |||
| 1462 | bool GMainWindow::ConfirmClose() { | 1515 | bool GMainWindow::ConfirmClose() { |
| 1463 | if (emu_thread == nullptr || !UISettings::values.confirm_before_closing) | 1516 | if (emu_thread == nullptr || !UISettings::values.confirm_before_closing) |
| 1464 | return true; | 1517 | return true; |
diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 3663d6aed..c8cbc0ba8 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include <QMainWindow> | 10 | #include <QMainWindow> |
| 11 | #include <QTimer> | 11 | #include <QTimer> |
| 12 | 12 | ||
| 13 | #include <boost/optional.hpp> | ||
| 13 | #include "common/common_types.h" | 14 | #include "common/common_types.h" |
| 14 | #include "core/core.h" | 15 | #include "core/core.h" |
| 15 | #include "ui_main.h" | 16 | #include "ui_main.h" |
| @@ -29,8 +30,9 @@ class WaitTreeWidget; | |||
| 29 | enum class GameListOpenTarget; | 30 | enum class GameListOpenTarget; |
| 30 | 31 | ||
| 31 | namespace FileSys { | 32 | namespace FileSys { |
| 33 | class RegisteredCacheUnion; | ||
| 32 | class VfsFilesystem; | 34 | class VfsFilesystem; |
| 33 | } | 35 | } // namespace FileSys |
| 34 | 36 | ||
| 35 | namespace Tegra { | 37 | namespace Tegra { |
| 36 | class DebugContext; | 38 | class DebugContext; |
| @@ -175,6 +177,8 @@ private slots: | |||
| 175 | void OnReinitializeKeys(ReinitializeKeyBehavior behavior); | 177 | void OnReinitializeKeys(ReinitializeKeyBehavior behavior); |
| 176 | 178 | ||
| 177 | private: | 179 | private: |
| 180 | boost::optional<u64> SelectRomFSDumpTarget(const FileSys::RegisteredCacheUnion&, | ||
| 181 | u64 program_id); | ||
| 178 | void UpdateStatusBar(); | 182 | void UpdateStatusBar(); |
| 179 | 183 | ||
| 180 | Ui::MainWindow ui; | 184 | Ui::MainWindow ui; |