fix: Multiplayer network fixes and airplane mode

- Auto-select network interface for direct connect/host room
- Always recreate ENet client on join for fresh bindings
- Add airplane mode toggle (Desktop & Android)
- Fix JWT verification with empty verify_uid
- Improve content-type handling for JWT endpoints

Signed-off-by: Zephyron <zephyron@citron-emu.org>
This commit is contained in:
Zephyron
2025-11-10 17:16:45 +10:00
parent 2943eebc9c
commit be5c2f772c
16 changed files with 129 additions and 15 deletions

View File

@@ -52,6 +52,7 @@ enum class ErrorModule : u32 {
Util = 33,
TIPC = 35,
ANIF = 37,
Module38 = 38, // Unknown/Undefined module - stubbed for multiplayer compatibility
CRT = 39,
ETHC = 100,
I2C = 101,

View File

@@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <array>
@@ -65,16 +66,30 @@ enum class FatalType : u32 {
static void GenerateErrorReport(Core::System& system, Result error_code, const FatalInfo& info) {
const auto title_id = system.GetApplicationProcessProgramID();
const auto module = static_cast<u32>(error_code.GetModule());
const auto description = static_cast<u32>(error_code.GetDescription());
// Check if this is module 38 (undefined/unknown module)
std::string module_note;
if (module == 38) {
module_note = fmt::format(
"\n⚠️ WARNING: Error module 38 is undefined/unknown!\n"
"This error may be game-generated or from an unimplemented service.\n"
"Error code: 2038-{:04d} (0x{:08X})\n"
"If you're experiencing multiplayer issues, this may be a stubbing issue.\n\n",
description, error_code.raw);
}
std::string crash_report = fmt::format(
"Citron {}-{} crash report\n"
"Title ID: {:016x}\n"
"Result: 0x{:X} ({:04}-{:04d})\n"
"Set flags: 0x{:16X}\n"
"Program entry point: 0x{:16X}\n"
"{}"
"\n",
Common::g_scm_branch, Common::g_scm_desc, title_id, error_code.raw,
2000 + static_cast<u32>(error_code.GetModule()),
static_cast<u32>(error_code.GetDescription()), info.set_flags, info.program_entry_point);
2000 + module, description, info.set_flags, info.program_entry_point, module_note);
if (info.backtrace_size != 0x0) {
crash_report += "Registers:\n";
for (size_t i = 0; i < info.registers.size(); i++) {

View File

@@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
@@ -24,4 +25,13 @@ constexpr Result ResultLocalCommunicationIdNotFound{ErrorModule::LDN, 97};
constexpr Result ResultLocalCommunicationVersionTooLow{ErrorModule::LDN, 113};
constexpr Result ResultLocalCommunicationVersionTooHigh{ErrorModule::LDN, 114};
// Module 38 error codes - Unknown/undefined module
// These are stubbed to prevent crashes during multiplayer
// Error code format: 2038-XXXX where XXXX is the description
constexpr Result ResultModule38Error2618{ErrorModule::Module38, 2618}; // Reported during multiplayer
constexpr Result ResultModule38Generic{ErrorModule::Module38, 0}; // Generic module 38 error
constexpr Result ResultModule38NetworkError{ErrorModule::Module38, 100}; // Network-related
constexpr Result ResultModule38ConnectionFailed{ErrorModule::Module38, 200}; // Connection failure
constexpr Result ResultModule38Timeout{ErrorModule::Module38, 300}; // Operation timeout
} // namespace Service::LDN

View File

@@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
@@ -187,6 +188,11 @@ std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
#endif
std::optional<NetworkInterface> GetSelectedNetworkInterface() {
// If airplane mode is enabled, return no interface (similar to Switch's airplane mode)
if (Settings::values.airplane_mode.GetValue()) {
return std::nullopt;
}
const auto& selected_network_interface = Settings::values.network_interface.GetValue();
const auto network_interfaces = Network::GetAvailableNetworkInterfaces();
if (network_interfaces.empty()) {