From 49166f0bd1c3ea4e48dcc95f406e60a68fba4c37 Mon Sep 17 00:00:00 2001 From: Gliniak Date: Wed, 26 Jun 2024 13:06:53 +0200 Subject: [PATCH] [Emulator] Added summary window to Install Content option --- src/xenia/app/emulator_window.cc | 56 +++++++++++++++++++++++++++----- src/xenia/emulator.cc | 19 ++++++++++- src/xenia/emulator.h | 9 ++++- src/xenia/xbox.h | 38 ++++++++++++++++++++++ 4 files changed, 111 insertions(+), 11 deletions(-) diff --git a/src/xenia/app/emulator_window.cc b/src/xenia/app/emulator_window.cc index ef4005e28..69ae89120 100644 --- a/src/xenia/app/emulator_window.cc +++ b/src/xenia/app/emulator_window.cc @@ -1045,20 +1045,58 @@ void EmulatorWindow::InstallContent() { return; } - for (auto path : paths) { + using content_installation_data = + std::tuple; + std::map> + content_installation_details; + + for (const auto& path : paths) { // Normalize the path and make absolute. auto abs_path = std::filesystem::absolute(path); - auto result = emulator_->InstallContentPackage(abs_path); - if (result != X_STATUS_SUCCESS) { - XELOGE("Failed to install content! Error code: {:08X}", result); + Emulator::ContentInstallationInfo installation_info; + auto result = emulator_->InstallContentPackage(abs_path, installation_info); - xe::ui::ImGuiDialog::ShowMessageBox( - imgui_drawer_.get(), "Failed to install content!", - "Failed to install content!\n\nCheck xenia.log for technical " - "details."); - } + auto entry = + content_installation_details.find(installation_info.content_type); + + // There is no entry with that specific type of XContent, so we must add it. + if (entry == content_installation_details.end()) { + content_installation_details.insert({installation_info.content_type, {}}); + entry = content_installation_details.find(installation_info.content_type); + }; + + entry->second.push_back({result, installation_info.content_name, + installation_info.installation_path}); } + + // Prepare installation process summary message + std::string summary = "Installation result: \n"; + + for (const auto& content_type : content_installation_details) { + if (XContentTypeMap.find(content_type.first) != XContentTypeMap.cend()) { + summary += XContentTypeMap.at(content_type.first) + ":\n"; + } else { + summary += "Unknown:\n"; + } + + for (const auto& content_installation_entry : content_type.second) { + const std::string status = + std::get<0>(content_installation_entry) == X_STATUS_SUCCESS + ? "Success" + : fmt::format("Failed (0x{:08X})", + std::get<0>(content_installation_entry)); + + summary += fmt::format("\t{} - {} => {}\n", status, + std::get<1>(content_installation_entry), + std::get<2>(content_installation_entry)); + } + + summary += "\n"; + } + + xe::ui::ImGuiDialog::ShowMessageBox(imgui_drawer_.get(), + "Content Installation Summary", summary); } void EmulatorWindow::ExtractZarchive() { diff --git a/src/xenia/emulator.cc b/src/xenia/emulator.cc index bc6a55458..0f18599de 100644 --- a/src/xenia/emulator.cc +++ b/src/xenia/emulator.cc @@ -593,9 +593,16 @@ X_STATUS Emulator::LaunchDefaultModule(const std::filesystem::path& path) { return result; } -X_STATUS Emulator::InstallContentPackage(const std::filesystem::path& path) { +X_STATUS Emulator::InstallContentPackage( + const std::filesystem::path& path, + ContentInstallationInfo& installation_info) { std::unique_ptr device = vfs::XContentContainerDevice::CreateContentDevice("", path); + + installation_info.content_name = "Invalid Content Package!"; + installation_info.content_type = static_cast(0); + installation_info.installation_path = xe::path_to_utf8(path.filename()); + if (!device || !device->Initialize()) { XELOGE("Failed to initialize device"); return X_STATUS_INVALID_PARAMETER; @@ -612,6 +619,15 @@ X_STATUS Emulator::InstallContentPackage(const std::filesystem::path& path) { content_root() / fmt::format("{:08X}", dev->title_id()) / "Headers" / fmt::format("{:08X}", dev->content_type()) / path.filename(); + installation_info.installation_path = + fmt::format("{:08X}/{:08X}/{}", dev->title_id(), dev->content_type(), + xe::path_to_utf8(path.filename())); + + installation_info.content_name = + xe::to_utf8(dev->content_header().display_name()); + installation_info.content_type = + static_cast(dev->content_type()); + if (std::filesystem::exists(installation_path)) { // TODO(Gliniak): Popup // Do you want to overwrite already existing data? @@ -619,6 +635,7 @@ X_STATUS Emulator::InstallContentPackage(const std::filesystem::path& path) { std::error_code error_code; std::filesystem::create_directories(installation_path, error_code); if (error_code) { + installation_info.content_name = "Cannot Create Content Directory!"; return error_code.value(); } } diff --git a/src/xenia/emulator.h b/src/xenia/emulator.h index f9f1835c6..04bd98058 100644 --- a/src/xenia/emulator.h +++ b/src/xenia/emulator.h @@ -223,8 +223,15 @@ class Emulator { X_STATUS LaunchDefaultModule(const std::filesystem::path& path); + struct ContentInstallationInfo { + XContentType content_type; + std::string installation_path; + std::string content_name; + }; + // Extract content of package to content specific directory. - X_STATUS InstallContentPackage(const std::filesystem::path& path); + X_STATUS InstallContentPackage(const std::filesystem::path& path, + ContentInstallationInfo& installation_info); // Extract content of zar package to desired directory. X_STATUS Emulator::ExtractZarchivePackage( diff --git a/src/xenia/xbox.h b/src/xenia/xbox.h index f46b163ea..e59b83827 100644 --- a/src/xenia/xbox.h +++ b/src/xenia/xbox.h @@ -10,6 +10,7 @@ #ifndef XENIA_XBOX_H_ #define XENIA_XBOX_H_ +#include #include #include "xenia/base/memory.h" @@ -438,6 +439,43 @@ enum class XContentType : uint32_t { kCommunityGame = 0x02000000, }; +const static std::map XContentTypeMap = { + {XContentType::kSavedGame, "Saved Game"}, + {XContentType::kMarketplaceContent, "Marketplace Content"}, + {XContentType::kPublisher, "Publisher"}, + {XContentType::kXbox360Title, "Xbox 360 Title"}, + {XContentType::kIptvPauseBuffer, "IPTV Pause Buffer"}, + {XContentType::kXNACommunity, "XNA Community"}, + {XContentType::kInstalledGame, "Installed Game"}, + {XContentType::kXboxTitle, "Xbox Title"}, + {XContentType::kSocialTitle, "Social Title"}, + {XContentType::kGamesOnDemand, "Game on Demand"}, + {XContentType::kSUStoragePack, "SU Storage Pack"}, + {XContentType::kAvatarItem, "Avatar Item"}, + {XContentType::kProfile, "Profile"}, + {XContentType::kGamerPicture, "Gamer Picture"}, + {XContentType::kTheme, "Theme"}, + {XContentType::kCacheFile, "Cache File"}, + {XContentType::kStorageDownload, "Storage Download"}, + {XContentType::kXboxSavedGame, "Xbox Saved Game"}, + {XContentType::kXboxDownload, "Xbox Download"}, + {XContentType::kGameDemo, "Game Demo"}, + {XContentType::kVideo, "Video"}, + {XContentType::kGameTitle, "Game Title"}, + {XContentType::kInstaller, "Installer"}, + {XContentType::kGameTrailer, "Game Trailer"}, + {XContentType::kArcadeTitle, "Arcade Title"}, + {XContentType::kXNA, "XNA"}, + {XContentType::kLicenseStore, "License Store"}, + {XContentType::kMovie, "Movie"}, + {XContentType::kTV, "TV"}, + {XContentType::kMusicVideo, "Music Video"}, + {XContentType::kGameVideo, "Game Video"}, + {XContentType::kPodcastVideo, "Podcast Video"}, + {XContentType::kViralVideo, "Viral Video"}, + {XContentType::kCommunityGame, "Community Game"}, +}; + enum class XDeploymentType : uint32_t { kOpticalDisc = 0, kHardDrive = 1, // Like extracted?