mirror of
https://github.com/izzy2lost/xenia-edge.git
synced 2026-07-06 00:20:26 -07:00
[App/Xam] Fix multi-disc issues
Properly handle launch flags and launch data, add disc/xex to title bar Fixes Orange Box, Rage, etc
This commit is contained in:
@@ -88,6 +88,7 @@
|
||||
#include "xenia/gpu/command_processor.h"
|
||||
#include "xenia/gpu/graphics_system.h"
|
||||
#include "xenia/hid/input_system.h"
|
||||
#include "xenia/kernel/user_module.h"
|
||||
#include "xenia/kernel/xam/profile_manager.h"
|
||||
#include "xenia/kernel/xam/xam_module.h"
|
||||
#include "xenia/kernel/xam/xam_state.h"
|
||||
@@ -1876,6 +1877,23 @@ void EmulatorWindow::UpdateTitle() {
|
||||
sb.Append(" v");
|
||||
sb.Append(title_version);
|
||||
}
|
||||
|
||||
// Show disc number for multi-disc titles and non-default XEX name
|
||||
auto executable_module = emulator()->kernel_state()->GetExecutableModule();
|
||||
if (executable_module) {
|
||||
if (executable_module->is_multi_disc_title()) {
|
||||
sb.AppendFormat(" Disc {}", executable_module->disc_number());
|
||||
}
|
||||
|
||||
// Show XEX name if it's not default.xex
|
||||
auto module_name = executable_module->name();
|
||||
auto module_name_lower = xe::utf8::lower_ascii(module_name);
|
||||
if (!module_name.empty() && module_name_lower != "default") {
|
||||
sb.Append(" ");
|
||||
sb.Append(module_name);
|
||||
}
|
||||
}
|
||||
|
||||
sb.Append("]");
|
||||
|
||||
auto title_name = emulator()->title_name();
|
||||
@@ -2366,8 +2384,12 @@ void EmulatorWindow::LaunchTitleInNewProcess(
|
||||
std::filesystem::path actual_path = path_to_file;
|
||||
std::string launch_module_arg;
|
||||
|
||||
std::string launch_flags_arg;
|
||||
std::string launch_data_arg;
|
||||
uint32_t launch_title_id = title_id;
|
||||
|
||||
if (for_launch_data) {
|
||||
// Read launch_data.txt to get the host_path and launch_path
|
||||
// Read launch_data.txt to get all launch parameters
|
||||
std::filesystem::path file_path(kernel::xam::kXamModuleLoaderDataFileName);
|
||||
std::ifstream file(file_path);
|
||||
if (!file.is_open()) {
|
||||
@@ -2392,12 +2414,18 @@ void EmulatorWindow::LaunchTitleInNewProcess(
|
||||
host_path = value;
|
||||
} else if (key == "launch_path") {
|
||||
launch_path = value;
|
||||
} else if (key == "launch_flags") {
|
||||
launch_flags_arg = value;
|
||||
} else if (key == "launch_data") {
|
||||
launch_data_arg = value;
|
||||
} else if (key == "title_id") {
|
||||
launch_title_id = std::stoul(value, nullptr, 16);
|
||||
}
|
||||
}
|
||||
|
||||
file.close();
|
||||
|
||||
// Delete launch_data.txt so new process doesn't try to process it
|
||||
// Delete launch_data.txt - we pass everything via command line
|
||||
std::filesystem::remove(kernel::xam::kXamModuleLoaderDataFileName);
|
||||
|
||||
// Use the host_path as the target and launch_path as --launch_module
|
||||
@@ -2413,8 +2441,8 @@ void EmulatorWindow::LaunchTitleInNewProcess(
|
||||
|
||||
// Load per-game config overrides if title_id is provided
|
||||
std::vector<std::string> game_config_args;
|
||||
if (title_id != 0) {
|
||||
auto title_id_str = fmt::format("{:08X}", title_id);
|
||||
if (launch_title_id != 0) {
|
||||
auto title_id_str = fmt::format("{:08X}", launch_title_id);
|
||||
game_config_args = config::LoadGameConfigAsArgs(title_id_str);
|
||||
}
|
||||
|
||||
@@ -2436,6 +2464,16 @@ void EmulatorWindow::LaunchTitleInNewProcess(
|
||||
u" --launch_module=\"" + xe::to_utf16(launch_module_arg) + u"\"";
|
||||
}
|
||||
|
||||
// Add --launch_flags if specified (for title-to-title launches)
|
||||
if (!launch_flags_arg.empty()) {
|
||||
cmd_line += u" --launch_flags=" + xe::to_utf16(launch_flags_arg);
|
||||
}
|
||||
|
||||
// Add --launch_data if specified (for title-to-title launches)
|
||||
if (!launch_data_arg.empty()) {
|
||||
cmd_line += u" --launch_data=" + xe::to_utf16(launch_data_arg);
|
||||
}
|
||||
|
||||
// Add per-game config overrides
|
||||
for (const auto& arg : game_config_args) {
|
||||
cmd_line += u" " + xe::to_utf16(arg);
|
||||
@@ -2509,6 +2547,20 @@ void EmulatorWindow::LaunchTitleInNewProcess(
|
||||
argv.push_back(launch_module_arg_str.c_str());
|
||||
}
|
||||
|
||||
// Add --launch_flags if specified (for title-to-title launches)
|
||||
std::string launch_flags_arg_str;
|
||||
if (!launch_flags_arg.empty()) {
|
||||
launch_flags_arg_str = "--launch_flags=" + launch_flags_arg;
|
||||
argv.push_back(launch_flags_arg_str.c_str());
|
||||
}
|
||||
|
||||
// Add --launch_data if specified (for title-to-title launches)
|
||||
std::string launch_data_arg_str;
|
||||
if (!launch_data_arg.empty()) {
|
||||
launch_data_arg_str = "--launch_data=" + launch_data_arg;
|
||||
argv.push_back(launch_data_arg_str.c_str());
|
||||
}
|
||||
|
||||
// Add per-game config overrides
|
||||
for (const auto& arg : game_config_args) {
|
||||
argv.push_back(arg.c_str());
|
||||
|
||||
@@ -138,6 +138,9 @@ DEFINE_bool(discord, true, "Enable Discord rich presence", "General");
|
||||
|
||||
DECLARE_bool(widescreen);
|
||||
|
||||
DECLARE_uint32(launch_flags);
|
||||
DECLARE_string(launch_data);
|
||||
|
||||
#if XE_PLATFORM_WIN32 && XE_ARCH_AMD64 == 1
|
||||
DEFINE_bool(enable_rdrand_ntdll_patch, false,
|
||||
"Hot-patches ntdll at the start of the process to not use rdrand "
|
||||
@@ -867,11 +870,32 @@ void EmulatorApp::EmulatorThread(bool is_game_process) {
|
||||
"xam.xex");
|
||||
|
||||
if (xam) {
|
||||
xam->LoadLoaderData();
|
||||
// Check if launch data was passed via command line (from UI process)
|
||||
// This takes precedence over launch_data.txt
|
||||
if (cvars::launch_flags != 0 || !cvars::launch_data.empty()) {
|
||||
auto& loader_data = xam->loader_data();
|
||||
loader_data.launch_data_present = true;
|
||||
loader_data.launch_flags = cvars::launch_flags;
|
||||
|
||||
if (xam->loader_data().launch_data_present) {
|
||||
const std::filesystem::path host_path = xam->loader_data().host_path;
|
||||
emulator_->LaunchPath(host_path);
|
||||
// Decode hex-encoded launch_data
|
||||
if (!cvars::launch_data.empty()) {
|
||||
loader_data.launch_data.clear();
|
||||
const std::string& hex = cvars::launch_data;
|
||||
for (size_t i = 0; i + 1 < hex.length(); i += 2) {
|
||||
std::string byte_str = hex.substr(i, 2);
|
||||
uint8_t byte =
|
||||
static_cast<uint8_t>(std::stoul(byte_str, nullptr, 16));
|
||||
loader_data.launch_data.push_back(byte);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Fall back to loading from file (legacy behavior)
|
||||
xam->LoadLoaderData();
|
||||
|
||||
if (xam->loader_data().launch_data_present) {
|
||||
const std::filesystem::path host_path = xam->loader_data().host_path;
|
||||
emulator_->LaunchPath(host_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -88,6 +88,16 @@ DEFINE_string(
|
||||
"module.",
|
||||
"General");
|
||||
|
||||
DEFINE_CVar(launch_flags, 0,
|
||||
"Launch flags passed from a title restart request. "
|
||||
"Used internally for title-to-title launches.",
|
||||
"General", true, uint32_t);
|
||||
|
||||
DEFINE_CVar(launch_data, "",
|
||||
"Hex-encoded launch data passed from a title restart request. "
|
||||
"Used internally for title-to-title launches.",
|
||||
"General", true, std::string);
|
||||
|
||||
DEFINE_bool(allow_game_relative_writes, false,
|
||||
"Not useful to non-developers. Allows code to write to paths "
|
||||
"relative to game://. Used for "
|
||||
|
||||
@@ -772,6 +772,13 @@ dword_result_t XamSwapDisc_entry(
|
||||
}
|
||||
}
|
||||
|
||||
// Update the host_path in loader_data so title restarts use the new
|
||||
// disc
|
||||
auto xam = kernel_state()->GetKernelModule<XamModule>("xam.xex");
|
||||
if (xam) {
|
||||
xam->loader_data().host_path = xe::path_to_utf8(new_disc_path);
|
||||
}
|
||||
|
||||
// Success - break out of the loop
|
||||
break;
|
||||
}
|
||||
@@ -779,6 +786,13 @@ dword_result_t XamSwapDisc_entry(
|
||||
XELOGW(
|
||||
"XamSwapDisc: Mounted device is not an XContentContainerDevice, "
|
||||
"skipping validation");
|
||||
|
||||
// Update the host_path in loader_data so title restarts use the new disc
|
||||
auto xam = kernel_state()->GetKernelModule<XamModule>("xam.xex");
|
||||
if (xam) {
|
||||
xam->loader_data().host_path = xe::path_to_utf8(new_disc_path);
|
||||
}
|
||||
|
||||
// For non-container devices, accept them (backward compatibility)
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -148,6 +148,7 @@ void XamModule::SaveLoaderData() {
|
||||
file << "host_path=" << host_path_as_string << "\n";
|
||||
file << "launch_path=" << launch_path << "\n";
|
||||
file << "launch_flags=" << loader_data_.launch_flags << "\n";
|
||||
file << "title_id=" << std::hex << kernel_state()->title_id() << "\n";
|
||||
|
||||
// Convert launch_data bytes to hex string
|
||||
if (!loader_data_.launch_data.empty()) {
|
||||
|
||||
Reference in New Issue
Block a user