Merge pull request #1959 from DarkLordZach/custom-rtc
settings: Add support for setting the RTC manually
This commit is contained in:
		| @@ -30,6 +30,7 @@ | |||||||
| #include "core/hle/service/sm/sm.h" | #include "core/hle/service/sm/sm.h" | ||||||
| #include "core/loader/loader.h" | #include "core/loader/loader.h" | ||||||
| #include "core/perf_stats.h" | #include "core/perf_stats.h" | ||||||
|  | #include "core/settings.h" | ||||||
| #include "core/telemetry_session.h" | #include "core/telemetry_session.h" | ||||||
| #include "frontend/applets/profile_select.h" | #include "frontend/applets/profile_select.h" | ||||||
| #include "frontend/applets/software_keyboard.h" | #include "frontend/applets/software_keyboard.h" | ||||||
| @@ -96,6 +97,11 @@ struct System::Impl { | |||||||
|         CoreTiming::Init(); |         CoreTiming::Init(); | ||||||
|         kernel.Initialize(); |         kernel.Initialize(); | ||||||
|  |  | ||||||
|  |         const auto current_time = std::chrono::duration_cast<std::chrono::seconds>( | ||||||
|  |             std::chrono::system_clock::now().time_since_epoch()); | ||||||
|  |         Settings::values.custom_rtc_differential = | ||||||
|  |             Settings::values.custom_rtc.value_or(current_time) - current_time; | ||||||
|  |  | ||||||
|         // Create a default fs if one doesn't already exist. |         // Create a default fs if one doesn't already exist. | ||||||
|         if (virtual_filesystem == nullptr) |         if (virtual_filesystem == nullptr) | ||||||
|             virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>(); |             virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>(); | ||||||
|   | |||||||
| @@ -12,9 +12,16 @@ | |||||||
| #include "core/hle/kernel/client_session.h" | #include "core/hle/kernel/client_session.h" | ||||||
| #include "core/hle/service/time/interface.h" | #include "core/hle/service/time/interface.h" | ||||||
| #include "core/hle/service/time/time.h" | #include "core/hle/service/time/time.h" | ||||||
|  | #include "core/settings.h" | ||||||
|  |  | ||||||
| namespace Service::Time { | namespace Service::Time { | ||||||
|  |  | ||||||
|  | static std::chrono::seconds GetSecondsSinceEpoch() { | ||||||
|  |     return std::chrono::duration_cast<std::chrono::seconds>( | ||||||
|  |                std::chrono::system_clock::now().time_since_epoch()) + | ||||||
|  |            Settings::values.custom_rtc_differential; | ||||||
|  | } | ||||||
|  |  | ||||||
| static void PosixToCalendar(u64 posix_time, CalendarTime& calendar_time, | static void PosixToCalendar(u64 posix_time, CalendarTime& calendar_time, | ||||||
|                             CalendarAdditionalInfo& additional_info, |                             CalendarAdditionalInfo& additional_info, | ||||||
|                             [[maybe_unused]] const TimeZoneRule& /*rule*/) { |                             [[maybe_unused]] const TimeZoneRule& /*rule*/) { | ||||||
| @@ -68,9 +75,7 @@ public: | |||||||
|  |  | ||||||
| private: | private: | ||||||
|     void GetCurrentTime(Kernel::HLERequestContext& ctx) { |     void GetCurrentTime(Kernel::HLERequestContext& ctx) { | ||||||
|         const s64 time_since_epoch{std::chrono::duration_cast<std::chrono::seconds>( |         const s64 time_since_epoch{GetSecondsSinceEpoch().count()}; | ||||||
|                                        std::chrono::system_clock::now().time_since_epoch()) |  | ||||||
|                                        .count()}; |  | ||||||
|         LOG_DEBUG(Service_Time, "called"); |         LOG_DEBUG(Service_Time, "called"); | ||||||
|  |  | ||||||
|         IPC::ResponseBuilder rb{ctx, 4}; |         IPC::ResponseBuilder rb{ctx, 4}; | ||||||
| @@ -266,10 +271,7 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) { | |||||||
|     IPC::RequestParser rp{ctx}; |     IPC::RequestParser rp{ctx}; | ||||||
|     const auto initial_type = rp.PopRaw<u8>(); |     const auto initial_type = rp.PopRaw<u8>(); | ||||||
|  |  | ||||||
|     const s64 time_since_epoch{std::chrono::duration_cast<std::chrono::seconds>( |     const s64 time_since_epoch{GetSecondsSinceEpoch().count()}; | ||||||
|                                    std::chrono::system_clock::now().time_since_epoch()) |  | ||||||
|                                    .count()}; |  | ||||||
|  |  | ||||||
|     const std::time_t time(time_since_epoch); |     const std::time_t time(time_since_epoch); | ||||||
|     const std::tm* tm = std::localtime(&time); |     const std::tm* tm = std::localtime(&time); | ||||||
|     if (tm == nullptr) { |     if (tm == nullptr) { | ||||||
|   | |||||||
| @@ -6,6 +6,7 @@ | |||||||
|  |  | ||||||
| #include <array> | #include <array> | ||||||
| #include <atomic> | #include <atomic> | ||||||
|  | #include <chrono> | ||||||
| #include <map> | #include <map> | ||||||
| #include <optional> | #include <optional> | ||||||
| #include <string> | #include <string> | ||||||
| @@ -350,6 +351,11 @@ struct Values { | |||||||
|     bool use_docked_mode; |     bool use_docked_mode; | ||||||
|     bool enable_nfc; |     bool enable_nfc; | ||||||
|     std::optional<u32> rng_seed; |     std::optional<u32> rng_seed; | ||||||
|  |     // Measured in seconds since epoch | ||||||
|  |     std::optional<std::chrono::seconds> custom_rtc; | ||||||
|  |     // Set on game boot, reset on stop. Seconds difference between current time and `custom_rtc` | ||||||
|  |     std::chrono::seconds custom_rtc_differential; | ||||||
|  |  | ||||||
|     s32 current_user; |     s32 current_user; | ||||||
|     s32 language_index; |     s32 language_index; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -419,13 +419,21 @@ void Config::ReadValues() { | |||||||
|  |  | ||||||
|     Settings::values.language_index = qt_config->value("language_index", 1).toInt(); |     Settings::values.language_index = qt_config->value("language_index", 1).toInt(); | ||||||
|  |  | ||||||
|     const auto enabled = qt_config->value("rng_seed_enabled", false).toBool(); |     const auto rng_seed_enabled = qt_config->value("rng_seed_enabled", false).toBool(); | ||||||
|     if (enabled) { |     if (rng_seed_enabled) { | ||||||
|         Settings::values.rng_seed = qt_config->value("rng_seed", 0).toULongLong(); |         Settings::values.rng_seed = qt_config->value("rng_seed", 0).toULongLong(); | ||||||
|     } else { |     } else { | ||||||
|         Settings::values.rng_seed = std::nullopt; |         Settings::values.rng_seed = std::nullopt; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     const auto custom_rtc_enabled = qt_config->value("custom_rtc_enabled", false).toBool(); | ||||||
|  |     if (custom_rtc_enabled) { | ||||||
|  |         Settings::values.custom_rtc = | ||||||
|  |             std::chrono::seconds(qt_config->value("custom_rtc", 0).toULongLong()); | ||||||
|  |     } else { | ||||||
|  |         Settings::values.custom_rtc = std::nullopt; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     qt_config->endGroup(); |     qt_config->endGroup(); | ||||||
|  |  | ||||||
|     qt_config->beginGroup("Miscellaneous"); |     qt_config->beginGroup("Miscellaneous"); | ||||||
| @@ -653,6 +661,11 @@ void Config::SaveValues() { | |||||||
|     qt_config->setValue("rng_seed_enabled", Settings::values.rng_seed.has_value()); |     qt_config->setValue("rng_seed_enabled", Settings::values.rng_seed.has_value()); | ||||||
|     qt_config->setValue("rng_seed", Settings::values.rng_seed.value_or(0)); |     qt_config->setValue("rng_seed", Settings::values.rng_seed.value_or(0)); | ||||||
|  |  | ||||||
|  |     qt_config->setValue("custom_rtc_enabled", Settings::values.custom_rtc.has_value()); | ||||||
|  |     qt_config->setValue("custom_rtc", | ||||||
|  |                         QVariant::fromValue<long long>( | ||||||
|  |                             Settings::values.custom_rtc.value_or(std::chrono::seconds{}).count())); | ||||||
|  |  | ||||||
|     qt_config->endGroup(); |     qt_config->endGroup(); | ||||||
|  |  | ||||||
|     qt_config->beginGroup("Miscellaneous"); |     qt_config->beginGroup("Miscellaneous"); | ||||||
|   | |||||||
| @@ -51,6 +51,12 @@ ConfigureSystem::ConfigureSystem(QWidget* parent) : QWidget(parent), ui(new Ui:: | |||||||
|             ui->rng_seed_edit->setText(QStringLiteral("00000000")); |             ui->rng_seed_edit->setText(QStringLiteral("00000000")); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|  |     connect(ui->custom_rtc_checkbox, &QCheckBox::stateChanged, this, [this](bool checked) { | ||||||
|  |         ui->custom_rtc_edit->setEnabled(checked); | ||||||
|  |         if (!checked) | ||||||
|  |             ui->custom_rtc_edit->setDateTime(QDateTime::currentDateTime()); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|     this->setConfiguration(); |     this->setConfiguration(); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -67,6 +73,13 @@ void ConfigureSystem::setConfiguration() { | |||||||
|     const auto rng_seed = |     const auto rng_seed = | ||||||
|         QString("%1").arg(Settings::values.rng_seed.value_or(0), 8, 16, QLatin1Char{'0'}).toUpper(); |         QString("%1").arg(Settings::values.rng_seed.value_or(0), 8, 16, QLatin1Char{'0'}).toUpper(); | ||||||
|     ui->rng_seed_edit->setText(rng_seed); |     ui->rng_seed_edit->setText(rng_seed); | ||||||
|  |  | ||||||
|  |     ui->custom_rtc_checkbox->setChecked(Settings::values.custom_rtc.has_value()); | ||||||
|  |     ui->custom_rtc_edit->setEnabled(Settings::values.custom_rtc.has_value()); | ||||||
|  |  | ||||||
|  |     const auto rtc_time = Settings::values.custom_rtc.value_or( | ||||||
|  |         std::chrono::seconds(QDateTime::currentSecsSinceEpoch())); | ||||||
|  |     ui->custom_rtc_edit->setDateTime(QDateTime::fromSecsSinceEpoch(rtc_time.count())); | ||||||
| } | } | ||||||
|  |  | ||||||
| void ConfigureSystem::ReadSystemSettings() {} | void ConfigureSystem::ReadSystemSettings() {} | ||||||
| @@ -82,6 +95,12 @@ void ConfigureSystem::applyConfiguration() { | |||||||
|     else |     else | ||||||
|         Settings::values.rng_seed = std::nullopt; |         Settings::values.rng_seed = std::nullopt; | ||||||
|  |  | ||||||
|  |     if (ui->custom_rtc_checkbox->isChecked()) | ||||||
|  |         Settings::values.custom_rtc = | ||||||
|  |             std::chrono::seconds(ui->custom_rtc_edit->dateTime().toSecsSinceEpoch()); | ||||||
|  |     else | ||||||
|  |         Settings::values.custom_rtc = std::nullopt; | ||||||
|  |  | ||||||
|     Settings::Apply(); |     Settings::Apply(); | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -22,6 +22,13 @@ | |||||||
|         <string>System Settings</string> |         <string>System Settings</string> | ||||||
|        </property> |        </property> | ||||||
|        <layout class="QGridLayout" name="gridLayout"> |        <layout class="QGridLayout" name="gridLayout"> | ||||||
|  |         <item row="2" column="0"> | ||||||
|  |          <widget class="QLabel" name="label_sound"> | ||||||
|  |           <property name="text"> | ||||||
|  |            <string>Sound output mode</string> | ||||||
|  |           </property> | ||||||
|  |          </widget> | ||||||
|  |         </item> | ||||||
|         <item row="1" column="1"> |         <item row="1" column="1"> | ||||||
|          <widget class="QComboBox" name="combo_language"> |          <widget class="QComboBox" name="combo_language"> | ||||||
|           <property name="toolTip"> |           <property name="toolTip"> | ||||||
| @@ -114,27 +121,6 @@ | |||||||
|           </item> |           </item> | ||||||
|          </widget> |          </widget> | ||||||
|         </item> |         </item> | ||||||
|         <item row="3" column="0"> |  | ||||||
|          <widget class="QLabel" name="label_console_id"> |  | ||||||
|           <property name="text"> |  | ||||||
|            <string>Console ID:</string> |  | ||||||
|           </property> |  | ||||||
|          </widget> |  | ||||||
|         </item> |  | ||||||
|         <item row="2" column="0"> |  | ||||||
|          <widget class="QLabel" name="label_sound"> |  | ||||||
|           <property name="text"> |  | ||||||
|            <string>Sound output mode</string> |  | ||||||
|           </property> |  | ||||||
|          </widget> |  | ||||||
|         </item> |  | ||||||
|         <item row="0" column="0"> |  | ||||||
|          <widget class="QLabel" name="label_birthday"> |  | ||||||
|           <property name="text"> |  | ||||||
|            <string>Birthday</string> |  | ||||||
|           </property> |  | ||||||
|          </widget> |  | ||||||
|         </item> |  | ||||||
|         <item row="0" column="1"> |         <item row="0" column="1"> | ||||||
|          <layout class="QHBoxLayout" name="horizontalLayout_birthday2"> |          <layout class="QHBoxLayout" name="horizontalLayout_birthday2"> | ||||||
|           <item> |           <item> | ||||||
| @@ -206,6 +192,20 @@ | |||||||
|           </item> |           </item> | ||||||
|          </layout> |          </layout> | ||||||
|         </item> |         </item> | ||||||
|  |         <item row="3" column="0"> | ||||||
|  |          <widget class="QLabel" name="label_console_id"> | ||||||
|  |           <property name="text"> | ||||||
|  |            <string>Console ID:</string> | ||||||
|  |           </property> | ||||||
|  |          </widget> | ||||||
|  |         </item> | ||||||
|  |         <item row="0" column="0"> | ||||||
|  |          <widget class="QLabel" name="label_birthday"> | ||||||
|  |           <property name="text"> | ||||||
|  |            <string>Birthday</string> | ||||||
|  |           </property> | ||||||
|  |          </widget> | ||||||
|  |         </item> | ||||||
|         <item row="3" column="1"> |         <item row="3" column="1"> | ||||||
|          <widget class="QPushButton" name="button_regenerate_console_id"> |          <widget class="QPushButton" name="button_regenerate_console_id"> | ||||||
|           <property name="sizePolicy"> |           <property name="sizePolicy"> | ||||||
| @@ -241,6 +241,13 @@ | |||||||
|           </item> |           </item> | ||||||
|          </widget> |          </widget> | ||||||
|         </item> |         </item> | ||||||
|  |         <item row="5" column="0"> | ||||||
|  |          <widget class="QCheckBox" name="rng_seed_checkbox"> | ||||||
|  |           <property name="text"> | ||||||
|  |            <string>RNG Seed</string> | ||||||
|  |           </property> | ||||||
|  |          </widget> | ||||||
|  |         </item> | ||||||
|         <item row="1" column="0"> |         <item row="1" column="0"> | ||||||
|          <widget class="QLabel" name="label_language"> |          <widget class="QLabel" name="label_language"> | ||||||
|           <property name="text"> |           <property name="text"> | ||||||
| @@ -248,14 +255,7 @@ | |||||||
|           </property> |           </property> | ||||||
|          </widget> |          </widget> | ||||||
|         </item> |         </item> | ||||||
|         <item row="4" column="0"> |         <item row="5" column="1"> | ||||||
|          <widget class="QCheckBox" name="rng_seed_checkbox"> |  | ||||||
|           <property name="text"> |  | ||||||
|            <string>RNG Seed</string> |  | ||||||
|           </property> |  | ||||||
|          </widget> |  | ||||||
|         </item> |  | ||||||
|         <item row="4" column="1"> |  | ||||||
|          <widget class="QLineEdit" name="rng_seed_edit"> |          <widget class="QLineEdit" name="rng_seed_edit"> | ||||||
|           <property name="sizePolicy"> |           <property name="sizePolicy"> | ||||||
|            <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> |            <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> | ||||||
| @@ -276,6 +276,27 @@ | |||||||
|           </property> |           </property> | ||||||
|          </widget> |          </widget> | ||||||
|         </item> |         </item> | ||||||
|  |         <item row="4" column="0"> | ||||||
|  |          <widget class="QCheckBox" name="custom_rtc_checkbox"> | ||||||
|  |           <property name="text"> | ||||||
|  |            <string>Custom RTC</string> | ||||||
|  |           </property> | ||||||
|  |          </widget> | ||||||
|  |         </item> | ||||||
|  |         <item row="4" column="1"> | ||||||
|  |          <widget class="QDateTimeEdit" name="custom_rtc_edit"> | ||||||
|  |           <property name="minimumDate"> | ||||||
|  |            <date> | ||||||
|  |             <year>1970</year> | ||||||
|  |             <month>1</month> | ||||||
|  |             <day>1</day> | ||||||
|  |            </date> | ||||||
|  |           </property> | ||||||
|  |           <property name="displayFormat"> | ||||||
|  |            <string>d MMM yyyy h:mm:ss AP</string> | ||||||
|  |           </property> | ||||||
|  |          </widget> | ||||||
|  |         </item> | ||||||
|        </layout> |        </layout> | ||||||
|       </widget> |       </widget> | ||||||
|      </item> |      </item> | ||||||
|   | |||||||
| @@ -325,13 +325,21 @@ void Config::ReadValues() { | |||||||
|     Settings::values.current_user = std::clamp<int>( |     Settings::values.current_user = std::clamp<int>( | ||||||
|         sdl2_config->GetInteger("System", "current_user", 0), 0, Service::Account::MAX_USERS - 1); |         sdl2_config->GetInteger("System", "current_user", 0), 0, Service::Account::MAX_USERS - 1); | ||||||
|  |  | ||||||
|     const auto enabled = sdl2_config->GetBoolean("System", "rng_seed_enabled", false); |     const auto rng_seed_enabled = sdl2_config->GetBoolean("System", "rng_seed_enabled", false); | ||||||
|     if (enabled) { |     if (rng_seed_enabled) { | ||||||
|         Settings::values.rng_seed = sdl2_config->GetInteger("System", "rng_seed", 0); |         Settings::values.rng_seed = sdl2_config->GetInteger("System", "rng_seed", 0); | ||||||
|     } else { |     } else { | ||||||
|         Settings::values.rng_seed = std::nullopt; |         Settings::values.rng_seed = std::nullopt; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     const auto custom_rtc_enabled = sdl2_config->GetBoolean("System", "custom_rtc_enabled", false); | ||||||
|  |     if (custom_rtc_enabled) { | ||||||
|  |         Settings::values.custom_rtc = | ||||||
|  |             std::chrono::seconds(sdl2_config->GetInteger("System", "custom_rtc", 0)); | ||||||
|  |     } else { | ||||||
|  |         Settings::values.custom_rtc = std::nullopt; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     // Core |     // Core | ||||||
|     Settings::values.use_cpu_jit = sdl2_config->GetBoolean("Core", "use_cpu_jit", true); |     Settings::values.use_cpu_jit = sdl2_config->GetBoolean("Core", "use_cpu_jit", true); | ||||||
|     Settings::values.use_multi_core = sdl2_config->GetBoolean("Core", "use_multi_core", false); |     Settings::values.use_multi_core = sdl2_config->GetBoolean("Core", "use_multi_core", false); | ||||||
|   | |||||||
| @@ -183,6 +183,12 @@ enable_nfc = | |||||||
| rng_seed_enabled = | rng_seed_enabled = | ||||||
| rng_seed = | rng_seed = | ||||||
|  |  | ||||||
|  | # Sets the current time (in seconds since 12:00 AM Jan 1, 1970) that will be used by the time service | ||||||
|  | # This will auto-increment, with the time set being the time the game is started | ||||||
|  | # This override will only occur if custom_rtc_enabled is true, otherwise the current time is used | ||||||
|  | custom_rtc_enabled = | ||||||
|  | custom_rtc = | ||||||
|  |  | ||||||
| # Sets the account username, max length is 32 characters | # Sets the account username, max length is 32 characters | ||||||
| # yuzu (default) | # yuzu (default) | ||||||
| username = yuzu | username = yuzu | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user