From 64062162c6b087f2cc043c2038b9bb604f26b492 Mon Sep 17 00:00:00 2001 From: DaemonTsun <96687758+DaemonTsun@users.noreply.github.com> Date: Sun, 20 Nov 2022 16:34:53 +0100 Subject: [PATCH] feat: add system time offset setting (#6139) * Add setting for system time offset Add a setting to displace citra system time by days, hours, minutes or seconds Add UI for the setting which is only visible when clock is set to system time Change core/settings.h to include the setting * Add system time offset to kernel Actually makes use of the time offset. * Fix time offset calculatioon in core/movie.cpp * Replace C++20 chrono::days with seconds Hopefully fixes the build. --- src/citra/config.cpp | 52 +++++++++++++++++++ src/citra_qt/configuration/config.cpp | 4 ++ .../configuration/configure_system.cpp | 23 +++++++- .../configuration/configure_system.ui | 45 +++++++++++++--- src/core/hle/kernel/shared_page.cpp | 10 ++++ src/core/movie.cpp | 14 +++-- src/core/settings.h | 1 + 7 files changed, 138 insertions(+), 11 deletions(-) diff --git a/src/citra/config.cpp b/src/citra/config.cpp index 78ce2e00c..18e0ad2e8 100644 --- a/src/citra/config.cpp +++ b/src/citra/config.cpp @@ -242,6 +242,58 @@ void Config::ReadValues() { .count(); } + { + constexpr const char* default_init_time_offset = "0 00:00:00"; + + std::string offset_string = + sdl2_config->GetString("System", "init_time_offset", default_init_time_offset); + + size_t sep_index = offset_string.find(' '); + + if (sep_index == std::string::npos) { + LOG_ERROR(Config, "Failed to parse init_time_offset. Using 0 00:00:00"); + offset_string = default_init_time_offset; + + sep_index = offset_string.find(' '); + } + + std::string day_string = offset_string.substr(0, sep_index); + long long days = 0; + + try { + days = std::stoll(day_string); + } catch (std::exception& e) { + LOG_ERROR(Config, "Failed to parse days in init_time_offset. Using 0"); + days = 0; + } + + long long days_in_seconds = days * 86400; + + std::tm t; + t.tm_sec = 0; + t.tm_min = 0; + t.tm_hour = 0; + t.tm_mday = 1; + t.tm_mon = 0; + t.tm_year = 100; + t.tm_isdst = 0; + + std::istringstream string_stream(offset_string.substr(sep_index + 1)); + string_stream >> std::get_time(&t, "%H:%M:%S"); + + if (string_stream.fail()) { + LOG_ERROR(Config, + "Failed to parse hours, minutes and seconds in init_time_offset. 00:00:00"); + } + + auto time_offset = + std::chrono::system_clock::from_time_t(std::mktime(&t)).time_since_epoch(); + + auto secs = std::chrono::duration_cast(time_offset).count(); + + Settings::values.init_time_offset = static_cast(secs) + days_in_seconds; + } + // Camera using namespace Service::CAM; Settings::values.camera_name[OuterRightCamera] = diff --git a/src/citra_qt/configuration/config.cpp b/src/citra_qt/configuration/config.cpp index d3fc3fbdc..a453341a7 100644 --- a/src/citra_qt/configuration/config.cpp +++ b/src/citra_qt/configuration/config.cpp @@ -547,6 +547,8 @@ void Config::ReadSystemValues() { .toInt()); Settings::values.init_time = ReadSetting(QStringLiteral("init_time"), 946681277ULL).toULongLong(); + Settings::values.init_time_offset = + ReadSetting(QStringLiteral("init_time_offset"), 0LL).toLongLong(); qt_config->endGroup(); } @@ -1057,6 +1059,8 @@ void Config::SaveSystemValues() { static_cast(Settings::InitClock::SystemTime)); WriteSetting(QStringLiteral("init_time"), static_cast(Settings::values.init_time), 946681277ULL); + WriteSetting(QStringLiteral("init_time_offset"), + static_cast(Settings::values.init_time_offset), 0LL); qt_config->endGroup(); } diff --git a/src/citra_qt/configuration/configure_system.cpp b/src/citra_qt/configuration/configure_system.cpp index 05ddcaa98..11b4fe77b 100644 --- a/src/citra_qt/configuration/configure_system.cpp +++ b/src/citra_qt/configuration/configure_system.cpp @@ -266,6 +266,14 @@ void ConfigureSystem::SetConfiguration() { date_time.setTime_t(Settings::values.init_time); ui->edit_init_time->setDateTime(date_time); + long long init_time_offset = Settings::values.init_time_offset; + long long days_offset = init_time_offset / 86400; + ui->edit_init_time_offset_days->setValue(days_offset); + + unsigned long long time_offset = std::abs(init_time_offset) - std::abs(days_offset * 86400); + QTime time = QTime::fromMSecsSinceStartOfDay(time_offset * 1000); + ui->edit_init_time_offset_time->setTime(time); + if (!enabled) { cfg = Service::CFG::GetModule(Core::System::GetInstance()); ASSERT_MSG(cfg, "CFG Module missing!"); @@ -382,6 +390,14 @@ void ConfigureSystem::ApplyConfiguration() { static_cast(ui->combo_init_clock->currentIndex()); Settings::values.init_time = ui->edit_init_time->dateTime().toTime_t(); + s64 time_offset_time = ui->edit_init_time_offset_time->time().msecsSinceStartOfDay() / 1000; + s64 time_offset_days = ui->edit_init_time_offset_days->value() * 86400; + + if (time_offset_days < 0) { + time_offset_time = -time_offset_time; + } + + Settings::values.init_time_offset = time_offset_days + time_offset_time; Settings::values.is_new_3ds = ui->toggle_new_3ds->isChecked(); } @@ -415,10 +431,10 @@ void ConfigureSystem::UpdateBirthdayComboBox(int birthmonth_index) { } void ConfigureSystem::ConfigureTime() { - ui->edit_init_time->setCalendarPopup(true); QDateTime dt; dt.fromString(QStringLiteral("2000-01-01 00:00:01"), QStringLiteral("yyyy-MM-dd hh:mm:ss")); ui->edit_init_time->setMinimumDateTime(dt); + ui->edit_init_time->setCalendarPopup(true); SetConfiguration(); @@ -428,8 +444,13 @@ void ConfigureSystem::ConfigureTime() { void ConfigureSystem::UpdateInitTime(int init_clock) { const bool is_fixed_time = static_cast(init_clock) == Settings::InitClock::FixedTime; + ui->label_init_time->setVisible(is_fixed_time); ui->edit_init_time->setVisible(is_fixed_time); + + ui->label_init_time_offset->setVisible(!is_fixed_time); + ui->edit_init_time_offset_days->setVisible(!is_fixed_time); + ui->edit_init_time_offset_time->setVisible(!is_fixed_time); } void ConfigureSystem::RefreshConsoleID() { diff --git a/src/citra_qt/configuration/configure_system.ui b/src/citra_qt/configuration/configure_system.ui index b48e166e1..37337f537 100644 --- a/src/citra_qt/configuration/configure_system.ui +++ b/src/citra_qt/configuration/configure_system.ui @@ -258,6 +258,44 @@ + + + + yyyy-MM-ddTHH:mm:ss + + + + + + + Offset time + + + + + + + + + days + + + -2147483648 + + + 2147483647 + + + + + + + HH:mm:ss + + + + + @@ -295,13 +333,6 @@ - - - - yyyy-MM-ddTHH:mm:ss - - - diff --git a/src/core/hle/kernel/shared_page.cpp b/src/core/hle/kernel/shared_page.cpp index 443ee930d..6deebf6b1 100644 --- a/src/core/hle/kernel/shared_page.cpp +++ b/src/core/hle/kernel/shared_page.cpp @@ -45,6 +45,16 @@ static std::chrono::seconds GetInitTime() { std::tm* now_tm = std::localtime(&now_time_t); if (now_tm && now_tm->tm_isdst > 0) now = now + std::chrono::hours(1); + + // add the offset + s64 init_time_offset = Settings::values.init_time_offset; + long long days_offset = init_time_offset / 86400; + long long days_offset_in_seconds = days_offset * 86400; // h/m/s truncated + unsigned long long seconds_offset = + std::abs(init_time_offset) - std::abs(days_offset_in_seconds); + + now = now + std::chrono::seconds(seconds_offset); + now = now + std::chrono::seconds(days_offset_in_seconds); return std::chrono::duration_cast(now.time_since_epoch()); } case Settings::InitClock::FixedTime: diff --git a/src/core/movie.cpp b/src/core/movie.cpp index c199443aa..cf74cc4ef 100644 --- a/src/core/movie.cpp +++ b/src/core/movie.cpp @@ -601,9 +601,17 @@ void Movie::PrepareForPlayback(const std::string& movie_file) { } void Movie::PrepareForRecording() { - init_time = (Settings::values.init_clock == Settings::InitClock::SystemTime - ? Common::Timer::GetTimeSinceJan1970().count() - : Settings::values.init_time); + if (Settings::values.init_clock == Settings::InitClock::SystemTime) { + long long init_time_offset = Settings::values.init_time_offset; + long long days_offset = init_time_offset / 86400; + unsigned long long seconds_offset = + std::abs(init_time_offset) - std::abs(days_offset * 86400); + + init_time = + Common::Timer::GetTimeSinceJan1970().count() + seconds_offset + (days_offset * 86400); + } else { + init_time = Settings::values.init_time; + } } Movie::ValidationResult Movie::ValidateMovie(const std::string& movie_file) const { diff --git a/src/core/settings.h b/src/core/settings.h index 2780ebd1c..accb39071 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -163,6 +163,7 @@ struct Values { int region_value; InitClock init_clock; u64 init_time; + s64 init_time_offset; // Renderer bool use_gles;