From ea1f2b114a9076d25d413b69f382f5ebcc2a8832 Mon Sep 17 00:00:00 2001 From: gibbed Date: Sat, 1 May 2021 17:18:38 -0500 Subject: [PATCH] [App] Improve title tracking. [App] Improve title tracking. [App] Show title version in emulator window title, when available. --- src/xenia/app/emulator_window.cc | 8 +++- src/xenia/emulator.cc | 66 ++++++++++++++++++++++++-------- src/xenia/emulator.h | 19 ++++++--- 3 files changed, 71 insertions(+), 22 deletions(-) diff --git a/src/xenia/app/emulator_window.cc b/src/xenia/app/emulator_window.cc index 41b2564a4..a47edf27b 100644 --- a/src/xenia/app/emulator_window.cc +++ b/src/xenia/app/emulator_window.cc @@ -435,7 +435,13 @@ void EmulatorWindow::UpdateTitle() { // Title information, if available if (emulator()->is_title_open()) { - sb.AppendFormat(u8" | [{:08X}]", emulator()->title_id()); + sb.AppendFormat(u8" | [{:08X}", emulator()->title_id()); + auto title_version = emulator()->title_version(); + if (!title_version.empty()) { + sb.Append(u8" v"); + sb.Append(title_version); + } + sb.Append(u8"]"); auto title_name = emulator()->title_name(); if (!title_name.empty()) { diff --git a/src/xenia/emulator.cc b/src/xenia/emulator.cc index 0511e61b4..e18f05644 100644 --- a/src/xenia/emulator.cc +++ b/src/xenia/emulator.cc @@ -68,7 +68,8 @@ Emulator::Emulator(const std::filesystem::path& command_line, storage_root_(storage_root), content_root_(content_root), cache_root_(cache_root), - game_title_(), + title_name_(), + title_version_(), display_window_(nullptr), memory_(), audio_system_(), @@ -78,7 +79,7 @@ Emulator::Emulator(const std::filesystem::path& command_line, file_system_(), kernel_state_(), main_thread_(), - title_id_(0), + title_id_({}), paused_(false), restoring_(false), restore_fence_() {} @@ -246,8 +247,9 @@ X_STATUS Emulator::TerminateTitle() { } kernel_state_->TerminateTitle(); - title_id_ = 0; - game_title_ = ""; + title_id_ = {}; + title_name_ = ""; + title_version_ = ""; on_terminate(); return X_STATUS_SUCCESS; } @@ -419,7 +421,10 @@ bool Emulator::SaveToFile(const std::filesystem::path& path) { // Save the emulator state to a file ByteStream stream(map->data(), map->size()); stream.Write('XSAV'); - stream.Write(title_id_); + stream.Write(title_id_.has_value()); + if (title_id_.has_value()) { + stream.Write(title_id_.value()); + } // It's important we don't hold the global lock here! XThreads need to step // forward (possibly through guarded regions) without worry! @@ -453,8 +458,15 @@ bool Emulator::RestoreFromFile(const std::filesystem::path& path) { return false; } - auto title_id = stream.Read(); - if (title_id != title_id_) { + auto has_title_id = stream.Read(); + std::optional title_id; + if (!has_title_id) { + title_id = {}; + } else { + title_id = stream.Read(); + } + if (title_id_.has_value() != title_id.has_value() || + title_id_.value() != title_id.value()) { // Swapping between titles is unsupported at the moment. assert_always(); return false; @@ -642,11 +654,28 @@ std::string Emulator::FindLaunchModule() { return path + default_module; } +static std::string format_version(xex2_version version) { + // fmt::format doesn't like bit fields + uint32_t major, minor, build, qfe; + major = version.major; + minor = version.minor; + build = version.build; + qfe = version.qfe; + if (qfe) { + return fmt::format("{}.{}.{}.{}", major, minor, build, qfe); + } + if (build) { + return fmt::format("{}.{}.{}", major, minor, build); + } + return fmt::format("{}.{}", major, minor); +} + X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path, const std::string_view module_path) { // Reset state. - title_id_ = 0; - game_title_ = ""; + title_id_ = {}; + title_name_ = ""; + title_version_ = ""; display_window_->SetIcon(nullptr, 0); // Allow xam to request module loads. @@ -662,8 +691,15 @@ X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path, // Grab the current title ID. xex2_opt_execution_info* info = nullptr; module->GetOptHeader(XEX_HEADER_EXECUTION_INFO, &info); - if (info) { + + if (!info) { + title_id_ = 0; + } else { title_id_ = info->title_id; + auto title_version = info->version(); + if (title_version.value != 0) { + title_version_ = format_version(title_version); + } } // Try and load the resource database (xex only). @@ -678,10 +714,10 @@ X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path, module->memory()->TranslateVirtual(resource_data), resource_size); if (db.is_valid()) { // TODO(gibbed): get title respective to user locale. - game_title_ = db.title(kernel::util::XdbfLocale::kEnglish); - if (game_title_.empty()) { + title_name_ = db.title(kernel::util::XdbfLocale::kEnglish); + if (title_name_.empty()) { // If English title is unavailable, get the title in default locale. - game_title_ = db.title(); + title_name_ = db.title(); } auto icon_block = db.icon(); if (icon_block) { @@ -696,7 +732,7 @@ X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path, // playing before the video can be seen if doing this in parallel with the // main thread. on_shader_storage_initialization(true); - graphics_system_->InitializeShaderStorage(cache_root_, title_id_, true); + graphics_system_->InitializeShaderStorage(cache_root_, title_id_.value(), true); on_shader_storage_initialization(false); auto main_thread = kernel_state_->LaunchModule(module); @@ -704,7 +740,7 @@ X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path, return X_STATUS_UNSUCCESSFUL; } main_thread_ = main_thread; - on_launch(title_id_, game_title_); + on_launch(title_id_.value(), title_name_); return X_STATUS_SUCCESS; } diff --git a/src/xenia/emulator.h b/src/xenia/emulator.h index 739c12b51..3b410e889 100644 --- a/src/xenia/emulator.h +++ b/src/xenia/emulator.h @@ -11,6 +11,7 @@ #define XENIA_EMULATOR_H_ #include +#include #include #include "xenia/base/delegate.h" @@ -65,14 +66,19 @@ class Emulator { // Folder files safe to remove without significant side effects are stored in. const std::filesystem::path& cache_root() const { return cache_root_; } - // Title of the game in the default language. - const std::string& game_title() const { return game_title_; } + // Name of the title in the default language. + const std::string& title_name() const { return title_name_; } + + // Version of the title as a string. + const std::string& title_version() const { return title_version_; } // Currently running title ID - uint32_t title_id() const { return title_id_; } + uint32_t title_id() const { + return !title_id_.has_value() ? 0 : title_id_.value(); + } // Are we currently running a title? - bool is_title_open() const { return title_id_ != 0; } + bool is_title_open() const { return title_id_.has_value(); } // Window used for displaying graphical output. ui::Window* display_window() const { return display_window_; } @@ -172,7 +178,8 @@ class Emulator { std::filesystem::path content_root_; std::filesystem::path cache_root_; - std::string game_title_; + std::string title_name_; + std::string title_version_; ui::Window* display_window_; @@ -188,7 +195,7 @@ class Emulator { std::unique_ptr kernel_state_; kernel::object_ref main_thread_; - uint32_t title_id_; // Currently running title ID + std::optional title_id_; // Currently running title ID bool paused_; bool restoring_;