[App] Improve title tracking.

[App] Improve title tracking.
[App] Show title version in emulator window title, when available.
This commit is contained in:
gibbed 2021-05-01 17:18:38 -05:00 committed by Rick Gibbed
parent 0419a9f13d
commit ea1f2b114a
3 changed files with 71 additions and 22 deletions

View File

@ -435,7 +435,13 @@ void EmulatorWindow::UpdateTitle() {
// Title information, if available // Title information, if available
if (emulator()->is_title_open()) { 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(); auto title_name = emulator()->title_name();
if (!title_name.empty()) { if (!title_name.empty()) {

View File

@ -68,7 +68,8 @@ Emulator::Emulator(const std::filesystem::path& command_line,
storage_root_(storage_root), storage_root_(storage_root),
content_root_(content_root), content_root_(content_root),
cache_root_(cache_root), cache_root_(cache_root),
game_title_(), title_name_(),
title_version_(),
display_window_(nullptr), display_window_(nullptr),
memory_(), memory_(),
audio_system_(), audio_system_(),
@ -78,7 +79,7 @@ Emulator::Emulator(const std::filesystem::path& command_line,
file_system_(), file_system_(),
kernel_state_(), kernel_state_(),
main_thread_(), main_thread_(),
title_id_(0), title_id_({}),
paused_(false), paused_(false),
restoring_(false), restoring_(false),
restore_fence_() {} restore_fence_() {}
@ -246,8 +247,9 @@ X_STATUS Emulator::TerminateTitle() {
} }
kernel_state_->TerminateTitle(); kernel_state_->TerminateTitle();
title_id_ = 0; title_id_ = {};
game_title_ = ""; title_name_ = "";
title_version_ = "";
on_terminate(); on_terminate();
return X_STATUS_SUCCESS; return X_STATUS_SUCCESS;
} }
@ -419,7 +421,10 @@ bool Emulator::SaveToFile(const std::filesystem::path& path) {
// Save the emulator state to a file // Save the emulator state to a file
ByteStream stream(map->data(), map->size()); ByteStream stream(map->data(), map->size());
stream.Write('XSAV'); 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 // It's important we don't hold the global lock here! XThreads need to step
// forward (possibly through guarded regions) without worry! // forward (possibly through guarded regions) without worry!
@ -453,8 +458,15 @@ bool Emulator::RestoreFromFile(const std::filesystem::path& path) {
return false; return false;
} }
auto title_id = stream.Read<uint32_t>(); auto has_title_id = stream.Read<bool>();
if (title_id != title_id_) { std::optional<uint32_t> title_id;
if (!has_title_id) {
title_id = {};
} else {
title_id = stream.Read<uint32_t>();
}
if (title_id_.has_value() != title_id.has_value() ||
title_id_.value() != title_id.value()) {
// Swapping between titles is unsupported at the moment. // Swapping between titles is unsupported at the moment.
assert_always(); assert_always();
return false; return false;
@ -642,11 +654,28 @@ std::string Emulator::FindLaunchModule() {
return path + default_module; 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, X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path,
const std::string_view module_path) { const std::string_view module_path) {
// Reset state. // Reset state.
title_id_ = 0; title_id_ = {};
game_title_ = ""; title_name_ = "";
title_version_ = "";
display_window_->SetIcon(nullptr, 0); display_window_->SetIcon(nullptr, 0);
// Allow xam to request module loads. // Allow xam to request module loads.
@ -662,8 +691,15 @@ X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path,
// Grab the current title ID. // Grab the current title ID.
xex2_opt_execution_info* info = nullptr; xex2_opt_execution_info* info = nullptr;
module->GetOptHeader(XEX_HEADER_EXECUTION_INFO, &info); module->GetOptHeader(XEX_HEADER_EXECUTION_INFO, &info);
if (info) {
if (!info) {
title_id_ = 0;
} else {
title_id_ = info->title_id; 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). // 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); module->memory()->TranslateVirtual(resource_data), resource_size);
if (db.is_valid()) { if (db.is_valid()) {
// TODO(gibbed): get title respective to user locale. // TODO(gibbed): get title respective to user locale.
game_title_ = db.title(kernel::util::XdbfLocale::kEnglish); title_name_ = db.title(kernel::util::XdbfLocale::kEnglish);
if (game_title_.empty()) { if (title_name_.empty()) {
// If English title is unavailable, get the title in default locale. // If English title is unavailable, get the title in default locale.
game_title_ = db.title(); title_name_ = db.title();
} }
auto icon_block = db.icon(); auto icon_block = db.icon();
if (icon_block) { 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 // playing before the video can be seen if doing this in parallel with the
// main thread. // main thread.
on_shader_storage_initialization(true); 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); on_shader_storage_initialization(false);
auto main_thread = kernel_state_->LaunchModule(module); auto main_thread = kernel_state_->LaunchModule(module);
@ -704,7 +740,7 @@ X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path,
return X_STATUS_UNSUCCESSFUL; return X_STATUS_UNSUCCESSFUL;
} }
main_thread_ = main_thread; main_thread_ = main_thread;
on_launch(title_id_, game_title_); on_launch(title_id_.value(), title_name_);
return X_STATUS_SUCCESS; return X_STATUS_SUCCESS;
} }

View File

@ -11,6 +11,7 @@
#define XENIA_EMULATOR_H_ #define XENIA_EMULATOR_H_
#include <functional> #include <functional>
#include <optional>
#include <string> #include <string>
#include "xenia/base/delegate.h" #include "xenia/base/delegate.h"
@ -65,14 +66,19 @@ class Emulator {
// Folder files safe to remove without significant side effects are stored in. // Folder files safe to remove without significant side effects are stored in.
const std::filesystem::path& cache_root() const { return cache_root_; } const std::filesystem::path& cache_root() const { return cache_root_; }
// Title of the game in the default language. // Name of the title in the default language.
const std::string& game_title() const { return game_title_; } 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 // 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? // 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. // Window used for displaying graphical output.
ui::Window* display_window() const { return display_window_; } ui::Window* display_window() const { return display_window_; }
@ -172,7 +178,8 @@ class Emulator {
std::filesystem::path content_root_; std::filesystem::path content_root_;
std::filesystem::path cache_root_; std::filesystem::path cache_root_;
std::string game_title_; std::string title_name_;
std::string title_version_;
ui::Window* display_window_; ui::Window* display_window_;
@ -188,7 +195,7 @@ class Emulator {
std::unique_ptr<kernel::KernelState> kernel_state_; std::unique_ptr<kernel::KernelState> kernel_state_;
kernel::object_ref<kernel::XThread> main_thread_; kernel::object_ref<kernel::XThread> main_thread_;
uint32_t title_id_; // Currently running title ID std::optional<uint32_t> title_id_; // Currently running title ID
bool paused_; bool paused_;
bool restoring_; bool restoring_;