[App] Improve title tracking.
[App] Improve title tracking. [App] Show title version in emulator window title, when available.
This commit is contained in:
parent
0419a9f13d
commit
ea1f2b114a
|
@ -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()) {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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_;
|
||||||
|
|
Loading…
Reference in New Issue