From 75ebfaa090ca5ba9757e984c545784221ad2bf6c Mon Sep 17 00:00:00 2001 From: lizzie Date: Sun, 15 Feb 2026 04:11:39 +0100 Subject: [PATCH] [common] autogenerate unique console serial for every install (#3550) Signed-off-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3550 Reviewed-by: Maufeat Reviewed-by: DraVee Co-authored-by: lizzie Co-committed-by: lizzie --- docs/user/Native.md | 5 +- src/common/settings.h | 10 +-- .../service/set/system_settings_server.cpp | 83 ++++++++++++++++--- src/frontend_common/settings_generator.cpp | 18 ++-- src/yuzu/configuration/configure_debug.cpp | 6 +- 5 files changed, 89 insertions(+), 33 deletions(-) diff --git a/docs/user/Native.md b/docs/user/Native.md index ec1cd02253..0d8ee81a7a 100644 --- a/docs/user/Native.md +++ b/docs/user/Native.md @@ -6,7 +6,4 @@ Debugging on physical hardware can get tedious and time consuming. Users are emp **Standard key prefix**: Allows to redirect the key manager to a file other than `prod.keys` (for example `other` would redirect to `other.keys`). This is useful for testing multiple keysets. Default is `prod`. -**Changing serial**: Very basic way to set debug values for the serial (and battery number). Developers do not need to write the full serial as it will be writen in-place (that is, it will be filled with the default serial and then overwrite the serial from the beginning). -- Battery serial: `YUZU0EMULATOR14022024` -- Board serial: `YUZ10000000001` -If the user were to set their board serial as `ABC`, then it will be written in-place and the resulting serial would be `ABC10000000001`. There are no underlying checks to ensure correctness of serials other than a hard limit of 16-characters for both. +**Changing serial**: Very basic way to set debug values for the serial (and battery number). Developers do not need to write the full serial as only the first digits (excluding the last) will be accoutned for. Region settings will affect the generated serial. The serial corresponds to a non-OLED/Lite console. diff --git a/src/common/settings.h b/src/common/settings.h index 9a7d3a30d3..a7cf800142 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -620,11 +620,11 @@ struct Values { "language_index", Category::System}; SwitchableSetting region_index{linkage, Region::Usa, "region_index", Category::System}; - SwitchableSetting time_zone_index{linkage, TimeZone::Auto, - "time_zone_index", Category::System}; + SwitchableSetting time_zone_index{linkage, TimeZone::Auto, "time_zone_index", Category::System}; + Setting serial_battery{linkage, 0, "serial_battery", Category::System}; + Setting serial_unit{linkage, 0, "serial_unit", Category::System}; // Measured in seconds since epoch - SwitchableSetting custom_rtc_enabled{ - linkage, false, "custom_rtc_enabled", Category::System, Specialization::Paired, true, true}; + SwitchableSetting custom_rtc_enabled{linkage, false, "custom_rtc_enabled", Category::System, Specialization::Paired, true, true}; SwitchableSetting custom_rtc{ linkage, 0, "custom_rtc", Category::System, Specialization::Time, false, true, &custom_rtc_enabled}; @@ -794,8 +794,6 @@ struct Values { true}; // Miscellaneous - Setting serial_battery{linkage, std::string(), "serial_battery", Category::Miscellaneous}; - Setting serial_unit{linkage, std::string(), "serial_unit", Category::Miscellaneous}; Setting log_filter{linkage, "*:Info", "log_filter", Category::Miscellaneous}; Setting log_flush_line{linkage, false, "flush_line", Category::Miscellaneous, Specialization::Default, true, true}; Setting censor_username{linkage, true, "censor_username", Category::Miscellaneous}; diff --git a/src/core/hle/service/set/system_settings_server.cpp b/src/core/hle/service/set/system_settings_server.cpp index f87dd847ba..87d6bf2a36 100644 --- a/src/core/hle/service/set/system_settings_server.cpp +++ b/src/core/hle/service/set/system_settings_server.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project @@ -980,25 +980,82 @@ Result ISystemSettingsServer::SetPrimaryAlbumStorage(PrimaryAlbumStorage primary R_SUCCEED(); } +static void Fill3DS_CRC(u32 d, char* data) { + std::array digits = { + u8((d / 1000000000) % 100), + u8((d / 100000000) % 10), + u8((d / 10000000) % 10), + u8((d / 1000000) % 10), + u8((d / 100000) % 10), + u8((d / 10000) % 10), + u8((d / 1000) % 10), + u8((d / 100) % 10), + u8((d / 10) % 10), + u8(d % 10), + }; + // Normalize to retail values + std::array retail_digits = { 1, 4, 5, 7 }; + digits[0] = retail_digits[(d % 10) % 4]; + digits[1] = 0; + // + for (size_t i = 0; i < sizeof(digits); ++i) + data[i] = char(digits[i] + '0'); + u8 sum_odd = 0, sum_even = 0; + for (size_t i = 0; i < sizeof(digits); i += 2) { + sum_odd += digits[i + 0]; + sum_even += digits[i + 1]; + } + u8 sum_digit = u8(((sum_even * 3) + sum_odd) % 10); + if (sum_digit != 0) + sum_digit = 10 - sum_digit; + data[sizeof(digits)] = char(sum_digit + '0'); +} + Result ISystemSettingsServer::GetBatteryLot(Out out_battery_lot) { LOG_INFO(Service_SET, "called"); - *out_battery_lot = {"YUZU0EMULATOR14022024"}; - if (auto const s = ::Settings::values.serial_battery.GetValue(); !s.empty()) { - auto const max_size = out_battery_lot->lot_number.size(); - auto const end = s.size() > max_size ? s.begin() + max_size : s.end(); - std::copy(s.begin(), end, out_battery_lot->lot_number.begin()); - } + *out_battery_lot = []{ + u32 d = ::Settings::values.serial_battery.GetValue(); + BatteryLot c{}; + c.lot_number[0] = 'B'; + c.lot_number[1] = 'H'; + c.lot_number[2] = 'A'; + c.lot_number[3] = 'C'; + // TODO: I have no fucking idea what the letters mean + c.lot_number[4] = 'H'; + c.lot_number[5] = 'Z'; + c.lot_number[6] = 'Z'; + c.lot_number[7] = 'A'; + c.lot_number[8] = 'D'; + c.lot_number[9] = char(((d / 100000) % 26) + 'A'); + Fill3DS_CRC(d, c.lot_number.data() + 10); + return c; + }(); R_SUCCEED(); } Result ISystemSettingsServer::GetSerialNumber(Out out_console_serial) { LOG_INFO(Service_SET, "called"); - *out_console_serial = {"YUZ10000000001"}; - if (auto const s = ::Settings::values.serial_unit.GetValue(); !s.empty()) { - auto const max_size = out_console_serial->serial_number.size(); - auto const end = s.size() > max_size ? s.begin() + max_size : s.end(); - std::copy(s.begin(), end, out_console_serial->serial_number.begin()); - } + *out_console_serial = []{ + u32 d = ::Settings::values.serial_unit.GetValue(); + SerialNumber c{}; + c.serial_number[0] = 'X'; + c.serial_number[1] = 'A'; + c.serial_number[2] = [] { + // Adding another setting would be tedious so... let's just reuse region_index :) + switch (::Settings::values.region_index.GetValue()) { + case ::Settings::Region::Japan: return 'J'; + case ::Settings::Region::Usa: return 'W'; + case ::Settings::Region::Europe: return 'E'; + case ::Settings::Region::Australia: return 'M'; //pretend its Malaysia + case ::Settings::Region::China: + case ::Settings::Region::Taiwan: return 'C'; + case ::Settings::Region::Korea: return 'K'; + default: return 'W'; + } + }(); + Fill3DS_CRC(d, c.serial_number.data() + 3); + return c; + }(); R_SUCCEED(); } diff --git a/src/frontend_common/settings_generator.cpp b/src/frontend_common/settings_generator.cpp index 0f09878b30..46625656b1 100644 --- a/src/frontend_common/settings_generator.cpp +++ b/src/frontend_common/settings_generator.cpp @@ -11,9 +11,8 @@ namespace FrontendCommon { void GenerateSettings() { static std::random_device rd; - // Web Token // - auto &token_setting = Settings::values.eden_token; - if (token_setting.GetValue().empty()) { + // Web Token + if (Settings::values.eden_token.GetValue().empty()) { static constexpr const size_t token_length = 48; static constexpr const frozen::string token_set = "abcdefghijklmnopqrstuvwxyz"; static std::uniform_int_distribution token_dist(0, token_set.size() - 1); @@ -23,9 +22,18 @@ void GenerateSettings() { size_t idx = token_dist(rd); result += token_set[idx]; } - - token_setting.SetValue(result); + Settings::values.eden_token.SetValue(result); } + + // Randomly generated number because, well, we fill the rest automagically ;) + // Other serial parts are filled by Region_Index + std::random_device device; + std::mt19937 gen(device()); + std::uniform_int_distribution distribution(1, (std::numeric_limits::max)()); + if (Settings::values.serial_unit.GetValue() == 0) + Settings::values.serial_unit.SetValue(distribution(gen)); + if (Settings::values.serial_battery.GetValue() == 0) + Settings::values.serial_battery.SetValue(distribution(gen)); } } diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp index 0de5f46dcc..bc835d35a2 100644 --- a/src/yuzu/configuration/configure_debug.cpp +++ b/src/yuzu/configuration/configure_debug.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: 2016 Citra Emulator Project @@ -57,10 +57,6 @@ void ConfigureDebug::SetConfiguration() { #endif // Immutable after starting - ui->serial_battery_edit->setEnabled(runtime_lock); - ui->serial_battery_edit->setText(QString::fromStdString(Settings::values.serial_battery.GetValue())); - ui->serial_board_edit->setEnabled(runtime_lock); - ui->serial_board_edit->setText(QString::fromStdString(Settings::values.serial_unit.GetValue())); ui->homebrew_args_edit->setEnabled(runtime_lock); ui->homebrew_args_edit->setText(QString::fromStdString(Settings::values.program_args.GetValue())); ui->toggle_console->setEnabled(runtime_lock);