Core: Add a file open dialog and refactor logic around loading new games

This commit is contained in:
Dr. Chat
2016-06-18 20:42:28 -05:00
parent dcd71c1613
commit b82f6a990a
5 changed files with 127 additions and 98 deletions

View File

@@ -177,8 +177,7 @@ X_STATUS Emulator::Setup(
return result;
}
X_STATUS Emulator::LaunchPath(std::wstring path,
std::function<void()> on_launch) {
X_STATUS Emulator::LaunchPath(std::wstring path) {
// Launch based on file type.
// This is a silly guess based on file extension.
auto last_slash = path.find_last_of(xe::kPathSeparator);
@@ -188,19 +187,18 @@ X_STATUS Emulator::LaunchPath(std::wstring path,
}
if (last_dot == std::wstring::npos) {
// Likely an STFS container.
return LaunchStfsContainer(path, on_launch);
return LaunchStfsContainer(path);
} else if (path.substr(last_dot) == L".xex" ||
path.substr(last_dot) == L".elf") {
// Treat as a naked xex file.
return LaunchXexFile(path, on_launch);
return LaunchXexFile(path);
} else {
// Assume a disc image.
return LaunchDiscImage(path, on_launch);
return LaunchDiscImage(path);
}
}
X_STATUS Emulator::LaunchXexFile(std::wstring path,
std::function<void()> on_launch) {
X_STATUS Emulator::LaunchXexFile(std::wstring path) {
// We create a virtual filesystem pointing to its directory and symlink
// that to the game filesystem.
// e.g., /my/files/foo.xex will get a local fs at:
@@ -232,11 +230,10 @@ X_STATUS Emulator::LaunchXexFile(std::wstring path,
// Launch the game.
std::string fs_path = "game:\\" + xe::to_string(file_name);
return CompleteLaunch(path, fs_path, on_launch);
return CompleteLaunch(path, fs_path);
}
X_STATUS Emulator::LaunchDiscImage(std::wstring path,
std::function<void()> on_launch) {
X_STATUS Emulator::LaunchDiscImage(std::wstring path) {
auto mount_path = "\\Device\\Cdrom0";
// Register the disc image in the virtual filesystem.
@@ -255,11 +252,10 @@ X_STATUS Emulator::LaunchDiscImage(std::wstring path,
file_system_->RegisterSymbolicLink("d:", mount_path);
// Launch the game.
return CompleteLaunch(path, "game:\\default.xex", on_launch);
return CompleteLaunch(path, "game:\\default.xex");
}
X_STATUS Emulator::LaunchStfsContainer(std::wstring path,
std::function<void()> on_launch) {
X_STATUS Emulator::LaunchStfsContainer(std::wstring path) {
auto mount_path = "\\Device\\Cdrom0";
// Register the container in the virtual filesystem.
@@ -278,7 +274,7 @@ X_STATUS Emulator::LaunchStfsContainer(std::wstring path,
file_system_->RegisterSymbolicLink("d:", mount_path);
// Launch the game.
return CompleteLaunch(path, "game:\\default.xex", on_launch);
return CompleteLaunch(path, "game:\\default.xex");
}
void Emulator::Pause() {
@@ -301,7 +297,9 @@ void Emulator::Pause() {
continue;
}
thread->thread()->Suspend(nullptr);
if (thread->is_running()) {
thread->thread()->Suspend(nullptr);
}
}
XELOGD("! EMULATOR PAUSED !");
@@ -326,7 +324,9 @@ void Emulator::Resume() {
continue;
}
thread->thread()->Resume(nullptr);
if (thread->is_running()) {
thread->thread()->Resume(nullptr);
}
}
}
@@ -485,68 +485,60 @@ void Emulator::WaitUntilExit() {
break;
}
}
on_exit();
}
X_STATUS Emulator::CompleteLaunch(const std::wstring& path,
const std::string& module_path,
std::function<void()> on_launch) {
const std::string& module_path) {
// Allow xam to request module loads.
auto xam = kernel_state()->GetKernelModule<kernel::xam::XamModule>("xam.xex");
X_STATUS result = X_STATUS_SUCCESS;
auto next_module = module_path;
while (next_module != "") {
XELOGI("Launching module %s", next_module.c_str());
auto module = kernel_state_->LoadUserModule(next_module.c_str());
if (!module) {
XELOGE("Failed to load user module %S", path.c_str());
return X_STATUS_NOT_FOUND;
}
XELOGI("Launching module %s", module_path.c_str());
auto module = kernel_state_->LoadUserModule(module_path.c_str());
if (!module) {
XELOGE("Failed to load user module %S", path.c_str());
return X_STATUS_NOT_FOUND;
}
kernel_state_->SetExecutableModule(module);
// Grab the current title ID.
xex2_opt_execution_info* info = nullptr;
module->GetOptHeader(XEX_HEADER_EXECUTION_INFO, &info);
if (info) {
title_id_ = info->title_id;
}
// Try and load the resource database (xex only).
if (module->title_id()) {
char title_id[9] = {0};
std::sprintf(title_id, "%08X", module->title_id());
uint32_t resource_data = 0;
uint32_t resource_size = 0;
if (XSUCCEEDED(
module->GetSection(title_id, &resource_data, &resource_size))) {
kernel::util::XdbfGameData db(
module->memory()->TranslateVirtual(resource_data), resource_size);
if (db.is_valid()) {
game_title_ = xe::to_wstring(db.title());
auto icon_block = db.icon();
if (icon_block) {
display_window_->SetIcon(icon_block.buffer, icon_block.size);
}
kernel_state_->SetExecutableModule(module);
// Try and load the resource database (xex only).
if (module->title_id()) {
char title_id[9] = {0};
std::sprintf(title_id, "%08X", module->title_id());
uint32_t resource_data = 0;
uint32_t resource_size = 0;
if (XSUCCEEDED(
module->GetSection(title_id, &resource_data, &resource_size))) {
kernel::util::XdbfGameData db(
module->memory()->TranslateVirtual(resource_data), resource_size);
if (db.is_valid()) {
game_title_ = xe::to_wstring(db.title());
auto icon_block = db.icon();
if (icon_block) {
display_window_->SetIcon(icon_block.buffer, icon_block.size);
}
}
}
auto main_xthread = module->Launch();
if (!main_xthread) {
return X_STATUS_UNSUCCESSFUL;
}
on_launch();
main_thread_ = main_xthread->thread();
WaitUntilExit();
// Check xam and see if they want us to load another module.
auto& loader_data = xam->loader_data();
next_module = loader_data.launch_path;
// And blank out the launch path to avoid an infinite loop.
loader_data.launch_path = "";
}
if (result == 0) {
return X_STATUS_SUCCESS;
} else {
auto main_xthread = module->Launch();
if (!main_xthread) {
return X_STATUS_UNSUCCESSFUL;
}
on_launch();
main_thread_ = main_xthread->thread();
return X_STATUS_SUCCESS;
}
} // namespace xe