early-access version 3636

This commit is contained in:
pineappleEA 2023-06-04 09:49:04 +02:00
parent 667703d3e1
commit 19ca7d484f
14 changed files with 167 additions and 2025 deletions

View file

@ -1,7 +1,7 @@
yuzu emulator early access yuzu emulator early access
============= =============
This is the source code for early-access 3635. This is the source code for early-access 3636.
## Legal Notice ## Legal Notice

View file

@ -1,6 +1,8 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
import android.annotation.SuppressLint
plugins { plugins {
id("com.android.application") id("com.android.application")
id("org.jetbrains.kotlin.android") id("org.jetbrains.kotlin.android")
@ -35,7 +37,7 @@ android {
jvmTarget = "17" jvmTarget = "17"
} }
packagingOptions { packaging {
// This is necessary for libadrenotools custom driver loading // This is necessary for libadrenotools custom driver loading
jniLibs.useLegacyPackaging = true jniLibs.useLegacyPackaging = true
} }
@ -58,6 +60,7 @@ android {
versionName = getGitVersion() versionName = getGitVersion()
ndk { ndk {
@SuppressLint("ChromeOsAbiSupport")
abiFilters += listOf("arm64-v8a") abiFilters += listOf("arm64-v8a")
} }

View file

@ -5,7 +5,6 @@ package org.yuzu.yuzu_emu.activities
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context
import android.content.DialogInterface
import android.content.Intent import android.content.Intent
import android.content.res.Configuration import android.content.res.Configuration
import android.graphics.Rect import android.graphics.Rect
@ -13,22 +12,28 @@ import android.hardware.Sensor
import android.hardware.SensorEvent import android.hardware.SensorEvent
import android.hardware.SensorEventListener import android.hardware.SensorEventListener
import android.hardware.SensorManager import android.hardware.SensorManager
import android.hardware.display.DisplayManager
import android.os.Bundle import android.os.Bundle
import android.view.Display
import android.view.InputDevice import android.view.InputDevice
import android.view.KeyEvent import android.view.KeyEvent
import android.view.MotionEvent import android.view.MotionEvent
import android.view.Surface import android.view.Surface
import android.view.View import android.view.View
import android.view.WindowManager
import android.view.inputmethod.InputMethodManager import android.view.inputmethod.InputMethodManager
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.preference.PreferenceManager import androidx.core.content.getSystemService
import com.google.android.material.dialog.MaterialAlertDialogBuilder import androidx.core.view.WindowCompat
import com.google.android.material.slider.Slider.OnChangeListener import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.window.layout.WindowInfoTracker
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.NativeLibrary import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.DialogSliderBinding
import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.fragments.EmulationFragment import org.yuzu.yuzu_emu.fragments.EmulationFragment
import org.yuzu.yuzu_emu.model.Game import org.yuzu.yuzu_emu.model.Game
import org.yuzu.yuzu_emu.utils.ControllerMappingHelper import org.yuzu.yuzu_emu.utils.ControllerMappingHelper
@ -44,7 +49,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
private var controllerMappingHelper: ControllerMappingHelper? = null private var controllerMappingHelper: ControllerMappingHelper? = null
var isActivityRecreated = false var isActivityRecreated = false
private var menuVisible = false
private var emulationFragment: EmulationFragment? = null private var emulationFragment: EmulationFragment? = null
private lateinit var nfcReader: NfcReader private lateinit var nfcReader: NfcReader
private lateinit var inputHandler: InputHandler private lateinit var inputHandler: InputHandler
@ -98,6 +102,14 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
inputHandler = InputHandler() inputHandler = InputHandler()
inputHandler.initialize() inputHandler.initialize()
lifecycleScope.launch(Dispatchers.Main) {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
WindowInfoTracker.getOrCreate(this@EmulationActivity)
.windowLayoutInfo(this@EmulationActivity)
.collect { emulationFragment?.updateCurrentLayout(this@EmulationActivity, it) }
}
}
// Start a foreground service to prevent the app from getting killed in the background // Start a foreground service to prevent the app from getting killed in the background
val startIntent = Intent(this, ForegroundService::class.java) val startIntent = Intent(this, ForegroundService::class.java)
startForegroundService(startIntent) startForegroundService(startIntent)
@ -241,20 +253,20 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
override fun onAccuracyChanged(sensor: Sensor, i: Int) {} override fun onAccuracyChanged(sensor: Sensor, i: Int) {}
private fun getAdjustedRotation():Int { private fun getAdjustedRotation():Int {
val rotation = windowManager.defaultDisplay.rotation; val rotation = getSystemService<DisplayManager>()!!.getDisplay(Display.DEFAULT_DISPLAY).rotation
val config: Configuration = resources.configuration val config: Configuration = resources.configuration
if ((config.screenLayout and Configuration.SCREENLAYOUT_LONG_YES) != 0 || if ((config.screenLayout and Configuration.SCREENLAYOUT_LONG_YES) != 0 ||
(config.screenLayout and Configuration.SCREENLAYOUT_LONG_NO) == 0) { (config.screenLayout and Configuration.SCREENLAYOUT_LONG_NO) == 0) {
return rotation; return rotation
} }
when (rotation) { when (rotation) {
Surface.ROTATION_0 -> return Surface.ROTATION_90; Surface.ROTATION_0 -> return Surface.ROTATION_90
Surface.ROTATION_90 -> return Surface.ROTATION_0; Surface.ROTATION_90 -> return Surface.ROTATION_0
Surface.ROTATION_180 -> return Surface.ROTATION_270; Surface.ROTATION_180 -> return Surface.ROTATION_270
Surface.ROTATION_270 -> return Surface.ROTATION_180; Surface.ROTATION_270 -> return Surface.ROTATION_180
} }
return rotation; return rotation
} }
private fun restoreState(savedInstanceState: Bundle) { private fun restoreState(savedInstanceState: Bundle) {
@ -262,18 +274,13 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
} }
private fun enableFullscreenImmersive() { private fun enableFullscreenImmersive() {
window.attributes.layoutInDisplayCutoutMode = WindowCompat.setDecorFitsSystemWindows(window, false)
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN) WindowInsetsControllerCompat(window, window.decorView).let { controller ->
controller.hide(WindowInsetsCompat.Type.systemBars())
// It would be nice to use IMMERSIVE_STICKY, but that doesn't show the toolbar. controller.systemBarsBehavior =
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or }
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or
View.SYSTEM_UI_FLAG_FULLSCREEN or
View.SYSTEM_UI_FLAG_IMMERSIVE
} }
private fun startMotionSensorListener() { private fun startMotionSensorListener() {

View file

@ -8,10 +8,13 @@ import android.app.AlertDialog
import android.content.Context import android.content.Context
import android.content.DialogInterface import android.content.DialogInterface
import android.content.SharedPreferences import android.content.SharedPreferences
import android.content.pm.ActivityInfo
import android.content.res.Resources
import android.graphics.Color import android.graphics.Color
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import android.util.TypedValue
import android.view.* import android.view.*
import android.widget.TextView import android.widget.TextView
import androidx.activity.OnBackPressedCallback import androidx.activity.OnBackPressedCallback
@ -20,8 +23,11 @@ import androidx.core.content.res.ResourcesCompat
import androidx.core.graphics.Insets import androidx.core.graphics.Insets
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import androidx.window.layout.FoldingFeature
import androidx.window.layout.WindowLayoutInfo
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.slider.Slider import com.google.android.material.slider.Slider
import org.yuzu.yuzu_emu.NativeLibrary import org.yuzu.yuzu_emu.NativeLibrary
@ -211,6 +217,33 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
} }
} }
private val Number.toPx get() = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), Resources.getSystem().displayMetrics).toInt()
fun updateCurrentLayout(emulationActivity: EmulationActivity, newLayoutInfo: WindowLayoutInfo) {
val isFolding = (newLayoutInfo.displayFeatures.find { it is FoldingFeature } as? FoldingFeature)?.let {
if (it.isSeparating) {
emulationActivity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
if (it.orientation == FoldingFeature.Orientation.HORIZONTAL) {
binding.surfaceEmulation.layoutParams.height = it.bounds.top
binding.inGameMenu.layoutParams.height = it.bounds.bottom
binding.overlayContainer.layoutParams.height = it.bounds.bottom - 48.toPx
binding.overlayContainer.updatePadding(0, 0, 0, 24.toPx)
}
}
it.isSeparating
} ?: false
if (!isFolding) {
binding.surfaceEmulation.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
binding.inGameMenu.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
binding.overlayContainer.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
binding.overlayContainer.updatePadding(0, 0, 0, 0)
emulationActivity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
}
binding.surfaceInputOverlay.requestLayout()
binding.inGameMenu.requestLayout()
binding.overlayContainer.requestLayout()
}
override fun surfaceCreated(holder: SurfaceHolder) { override fun surfaceCreated(holder: SurfaceHolder) {
// We purposely don't do anything here. // We purposely don't do anything here.
// All work is done in surfaceChanged, which we are guaranteed to get even for surface creation. // All work is done in surfaceChanged, which we are guaranteed to get even for surface creation.

View file

@ -20,6 +20,12 @@
android:focusable="false" android:focusable="false"
android:focusableInTouchMode="false" /> android:focusableInTouchMode="false" />
<FrameLayout
android:id="@+id/overlay_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="bottom">
<!-- This is the onscreen input overlay --> <!-- This is the onscreen input overlay -->
<org.yuzu.yuzu_emu.overlay.InputOverlay <org.yuzu.yuzu_emu.overlay.InputOverlay
android:id="@+id/surface_input_overlay" android:id="@+id/surface_input_overlay"
@ -48,6 +54,7 @@
android:layout_gravity="center" android:layout_gravity="center"
android:text="@string/emulation_done" android:text="@string/emulation_done"
android:visibility="gone" /> android:visibility="gone" />
</FrameLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>
@ -55,7 +62,7 @@
android:id="@+id/in_game_menu" android:id="@+id/in_game_menu"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_gravity="start" android:layout_gravity="start|bottom"
app:headerLayout="@layout/header_in_game" app:headerLayout="@layout/header_in_game"
app:menu="@menu/menu_in_game" /> app:menu="@menu/menu_in_game" />

View file

@ -1,16 +1,12 @@
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#if __cpp_lib_chrono >= 201907L
#include <chrono>
#endif
#include <string_view> #include <string_view>
#include "common/assert.h" #include "common/assert.h"
#include "common/fs/path_util.h" #include "common/fs/path_util.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/settings.h" #include "common/settings.h"
#include "common/time_zone.h"
namespace Settings { namespace Settings {
@ -18,23 +14,18 @@ Values values;
static bool configuring_global = true; static bool configuring_global = true;
std::string GetTimeZoneString() { std::string GetTimeZoneString() {
const auto time_zone_index = static_cast<std::size_t>(values.time_zone_index.GetValue()); static constexpr std::array timezones{
ASSERT(time_zone_index < Common::TimeZone::GetTimeZoneStrings().size()); "auto", "default", "CET", "CST6CDT", "Cuba", "EET", "Egypt", "Eire",
"EST", "EST5EDT", "GB", "GB-Eire", "GMT", "GMT+0", "GMT-0", "GMT0",
"Greenwich", "Hongkong", "HST", "Iceland", "Iran", "Israel", "Jamaica", "Japan",
"Kwajalein", "Libya", "MET", "MST", "MST7MDT", "Navajo", "NZ", "NZ-CHAT",
"Poland", "Portugal", "PRC", "PST8PDT", "ROC", "ROK", "Singapore", "Turkey",
"UCT", "Universal", "UTC", "W-SU", "WET", "Zulu",
};
std::string location_name; const auto time_zone_index = static_cast<std::size_t>(values.time_zone_index.GetValue());
if (time_zone_index == 0) { // Auto ASSERT(time_zone_index < timezones.size());
#if __cpp_lib_chrono >= 201907L return timezones[time_zone_index];
const struct std::chrono::tzdb& time_zone_data = std::chrono::get_tzdb();
const std::chrono::time_zone* current_zone = time_zone_data.current_zone();
std::string_view current_zone_name = current_zone->name();
location_name = current_zone_name;
#else
location_name = Common::TimeZone::FindSystemTimeZone();
#endif
} else {
location_name = Common::TimeZone::GetTimeZoneStrings()[time_zone_index];
}
return location_name;
} }
void LogSettings() { void LogSettings() {

View file

@ -4,29 +4,12 @@
#include <chrono> #include <chrono>
#include <iomanip> #include <iomanip>
#include <sstream> #include <sstream>
#include <fmt/chrono.h>
#include <fmt/core.h>
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/settings.h"
#include "common/time_zone.h" #include "common/time_zone.h"
namespace Common::TimeZone { namespace Common::TimeZone {
// Time zone strings
constexpr std::array timezones{
"GMT", "GMT", "CET", "CST6CDT", "Cuba", "EET", "Egypt", "Eire",
"EST", "EST5EDT", "GB", "GB-Eire", "GMT", "GMT+0", "GMT-0", "GMT0",
"Greenwich", "Hongkong", "HST", "Iceland", "Iran", "Israel", "Jamaica", "Japan",
"Kwajalein", "Libya", "MET", "MST", "MST7MDT", "Navajo", "NZ", "NZ-CHAT",
"Poland", "Portugal", "PRC", "PST8PDT", "ROC", "ROK", "Singapore", "Turkey",
"UCT", "Universal", "UTC", "W-SU", "WET", "Zulu",
};
const std::array<const char*, 46>& GetTimeZoneStrings() {
return timezones;
}
std::string GetDefaultTimeZone() { std::string GetDefaultTimeZone() {
return "GMT"; return "GMT";
} }
@ -35,7 +18,10 @@ static std::string GetOsTimeZoneOffset() {
const std::time_t t{std::time(nullptr)}; const std::time_t t{std::time(nullptr)};
const std::tm tm{*std::localtime(&t)}; const std::tm tm{*std::localtime(&t)};
return fmt::format("{:%z}", tm); std::stringstream ss;
ss << std::put_time(&tm, "%z"); // Get the current timezone offset, e.g. "-400", as a string
return ss.str();
} }
static int ConvertOsTimeZoneOffsetToInt(const std::string& timezone) { static int ConvertOsTimeZoneOffsetToInt(const std::string& timezone) {
@ -59,57 +45,4 @@ std::chrono::seconds GetCurrentOffsetSeconds() {
return std::chrono::seconds{seconds}; return std::chrono::seconds{seconds};
} }
std::string FindSystemTimeZone() {
#if defined(MINGW)
// MinGW has broken strftime -- https://sourceforge.net/p/mingw-w64/bugs/793/
// e.g. fmt::format("{:%z}") -- returns "Eastern Daylight Time" when it should be "-0400"
return timezones[0];
#else
// Time zone offset in seconds from GMT
constexpr std::array offsets{
0, 0, 3600, -21600, -19768, 7200, 7509, -1521, -18000, -18000, -75, -75,
0, 0, 0, 0, 0, 27402, -36000, -968, 12344, 8454, -18430, 33539,
40160, 3164, 3600, -25200, -25200, -25196, 41944, 44028, 5040, -2205, 29143, -28800,
29160, 30472, 24925, 6952, 0, 0, 0, 9017, 0, 0,
};
// If the time zone recognizes Daylight Savings Time
constexpr std::array dst{
false, false, true, true, true, true, true, true, false, true, true, true,
false, false, false, false, false, true, false, false, true, true, true, true,
false, true, true, false, true, true, true, true, true, true, true, true,
true, true, true, true, false, false, false, true, true, false,
};
static std::string system_time_zone_cached{};
if (!system_time_zone_cached.empty()) {
return system_time_zone_cached;
}
const auto now = std::time(nullptr);
const struct std::tm& local = *std::localtime(&now);
const s64 system_offset = GetCurrentOffsetSeconds().count() - (local.tm_isdst ? 3600 : 0);
int min = std::numeric_limits<int>::max();
int min_index = -1;
for (u32 i = 2; i < offsets.size(); i++) {
// Skip if system is celebrating DST but considered time zone does not
if (local.tm_isdst && !dst[i]) {
continue;
}
const auto offset = offsets[i];
const int difference = static_cast<int>(std::abs(offset - system_offset));
if (difference < min) {
min = difference;
min_index = i;
}
}
system_time_zone_cached = GetTimeZoneStrings()[min_index];
return system_time_zone_cached;
#endif
}
} // namespace Common::TimeZone } // namespace Common::TimeZone

View file

@ -3,21 +3,15 @@
#pragma once #pragma once
#include <array>
#include <chrono> #include <chrono>
#include <string> #include <string>
namespace Common::TimeZone { namespace Common::TimeZone {
[[nodiscard]] const std::array<const char*, 46>& GetTimeZoneStrings();
/// Gets the default timezone, i.e. "GMT" /// Gets the default timezone, i.e. "GMT"
[[nodiscard]] std::string GetDefaultTimeZone(); [[nodiscard]] std::string GetDefaultTimeZone();
/// Gets the offset of the current timezone (from the default), in seconds /// Gets the offset of the current timezone (from the default), in seconds
[[nodiscard]] std::chrono::seconds GetCurrentOffsetSeconds(); [[nodiscard]] std::chrono::seconds GetCurrentOffsetSeconds();
/// Searches time zone offsets for the closest offset to the system time zone
[[nodiscard]] std::string FindSystemTimeZone();
} // namespace Common::TimeZone } // namespace Common::TimeZone

File diff suppressed because it is too large Load diff

View file

@ -22,6 +22,10 @@ s64 GetSecondsSinceEpoch() {
return std::chrono::duration_cast<std::chrono::seconds>(time_since_epoch).count() + return std::chrono::duration_cast<std::chrono::seconds>(time_since_epoch).count() +
Settings::values.custom_rtc_differential; Settings::values.custom_rtc_differential;
} }
s64 GetExternalRtcValue() {
return GetSecondsSinceEpoch() + TimeManager::GetExternalTimeZoneOffset();
}
} // Anonymous namespace } // Anonymous namespace
struct TimeManager::Impl final { struct TimeManager::Impl final {
@ -39,7 +43,7 @@ struct TimeManager::Impl final {
std::make_shared<Clock::EphemeralNetworkSystemClockContextWriter>()}, std::make_shared<Clock::EphemeralNetworkSystemClockContextWriter>()},
time_zone_content_manager{system} { time_zone_content_manager{system} {
const auto system_time{Clock::TimeSpanType::FromSeconds(GetSecondsSinceEpoch())}; const auto system_time{Clock::TimeSpanType::FromSeconds(GetExternalRtcValue())};
SetupStandardSteadyClock(system, Common::UUID::MakeRandom(), system_time, {}, {}); SetupStandardSteadyClock(system, Common::UUID::MakeRandom(), system_time, {}, {});
SetupStandardLocalSystemClock(system, {}, system_time.ToSeconds()); SetupStandardLocalSystemClock(system, {}, system_time.ToSeconds());
@ -119,6 +123,14 @@ struct TimeManager::Impl final {
time_zone_content_manager.GetTimeZoneManager().MarkAsInitialized(); time_zone_content_manager.GetTimeZoneManager().MarkAsInitialized();
} }
static s64 GetExternalTimeZoneOffset() {
// With "auto" timezone setting, we use the external system's timezone offset
if (Settings::GetTimeZoneString() == "auto") {
return Common::TimeZone::GetCurrentOffsetSeconds().count();
}
return 0;
}
void SetupStandardSteadyClock(Core::System& system_, Common::UUID clock_source_id, void SetupStandardSteadyClock(Core::System& system_, Common::UUID clock_source_id,
Clock::TimeSpanType setup_value, Clock::TimeSpanType setup_value,
Clock::TimeSpanType internal_offset, bool is_rtc_reset_detected) { Clock::TimeSpanType internal_offset, bool is_rtc_reset_detected) {
@ -289,4 +301,13 @@ void TimeManager::SetupTimeZoneManager(std::string location_name,
impl->SetupTimeZoneManager(location_name, time_zone_updated_time_point, impl->SetupTimeZoneManager(location_name, time_zone_updated_time_point,
total_location_name_count, time_zone_rule_version, vfs_file); total_location_name_count, time_zone_rule_version, vfs_file);
} }
/*static*/ s64 TimeManager::GetExternalTimeZoneOffset() {
// With "auto" timezone setting, we use the external system's timezone offset
if (Settings::GetTimeZoneString() == "auto") {
return Common::TimeZone::GetCurrentOffsetSeconds().count();
}
return 0;
}
} // namespace Service::Time } // namespace Service::Time

View file

@ -64,6 +64,8 @@ public:
std::size_t total_location_name_count, u128 time_zone_rule_version, std::size_t total_location_name_count, u128 time_zone_rule_version,
FileSys::VirtualFile& vfs_file); FileSys::VirtualFile& vfs_file);
static s64 GetExternalTimeZoneOffset();
private: private:
Core::System& system; Core::System& system;

View file

@ -1,7 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <chrono>
#include <sstream> #include <sstream>
#include "common/logging/log.h" #include "common/logging/log.h"
@ -13,11 +12,7 @@
#include "core/file_sys/registered_cache.h" #include "core/file_sys/registered_cache.h"
#include "core/file_sys/romfs.h" #include "core/file_sys/romfs.h"
#include "core/file_sys/system_archive/system_archive.h" #include "core/file_sys/system_archive/system_archive.h"
#include "core/file_sys/vfs.h"
#include "core/file_sys/vfs_types.h"
#include "core/hle/result.h"
#include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/time/errors.h"
#include "core/hle/service/time/time_manager.h" #include "core/hle/service/time/time_manager.h"
#include "core/hle/service/time/time_zone_content_manager.h" #include "core/hle/service/time/time_zone_content_manager.h"
@ -76,14 +71,20 @@ TimeZoneContentManager::TimeZoneContentManager(Core::System& system_)
: system{system_}, location_name_cache{BuildLocationNameCache(system)} {} : system{system_}, location_name_cache{BuildLocationNameCache(system)} {}
void TimeZoneContentManager::Initialize(TimeManager& time_manager) { void TimeZoneContentManager::Initialize(TimeManager& time_manager) {
std::string location_name;
const auto timezone_setting = Settings::GetTimeZoneString(); const auto timezone_setting = Settings::GetTimeZoneString();
if (timezone_setting == "auto" || timezone_setting == "default") {
location_name = Common::TimeZone::GetDefaultTimeZone();
} else {
location_name = timezone_setting;
}
if (FileSys::VirtualFile vfs_file; if (FileSys::VirtualFile vfs_file;
GetTimeZoneInfoFile(timezone_setting, vfs_file) == ResultSuccess) { GetTimeZoneInfoFile(location_name, vfs_file) == ResultSuccess) {
const auto time_point{ const auto time_point{
time_manager.GetStandardSteadyClockCore().GetCurrentTimePoint(system)}; time_manager.GetStandardSteadyClockCore().GetCurrentTimePoint(system)};
time_manager.SetupTimeZoneManager(timezone_setting, time_point, location_name_cache.size(), time_manager.SetupTimeZoneManager(location_name, time_point, location_name_cache.size(), {},
{}, vfs_file); vfs_file);
} else { } else {
time_zone_manager.MarkAsInitialized(); time_zone_manager.MarkAsInitialized();
} }
@ -125,14 +126,7 @@ Result TimeZoneContentManager::GetTimeZoneInfoFile(const std::string& location_n
vfs_file = zoneinfo_dir->GetFileRelative(location_name); vfs_file = zoneinfo_dir->GetFileRelative(location_name);
if (!vfs_file) { if (!vfs_file) {
LOG_WARNING(Service_Time, "{:016X} has no file \"{}\"! Using system timezone.", LOG_ERROR(Service_Time, "{:016X} has no file \"{}\"! Using default timezone.",
time_zone_binary_titleid, location_name);
const std::string system_time_zone{Common::TimeZone::FindSystemTimeZone()};
vfs_file = zoneinfo_dir->GetFile(system_time_zone);
}
if (!vfs_file) {
LOG_WARNING(Service_Time, "{:016X} has no file \"{}\"! Using default timezone.",
time_zone_binary_titleid, location_name); time_zone_binary_titleid, location_name);
vfs_file = zoneinfo_dir->GetFile(Common::TimeZone::GetDefaultTimeZone()); vfs_file = zoneinfo_dir->GetFile(Common::TimeZone::GetDefaultTimeZone());
} }

View file

@ -2,7 +2,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <climits> #include <climits>
#include <limits>
#include "common/assert.h" #include "common/assert.h"
#include "common/logging/log.h" #include "common/logging/log.h"
@ -10,7 +9,6 @@
#include "core/file_sys/nca_metadata.h" #include "core/file_sys/nca_metadata.h"
#include "core/file_sys/registered_cache.h" #include "core/file_sys/registered_cache.h"
#include "core/hle/service/time/time_zone_manager.h" #include "core/hle/service/time/time_zone_manager.h"
#include "core/hle/service/time/time_zone_types.h"
namespace Service::Time::TimeZone { namespace Service::Time::TimeZone {
@ -144,9 +142,6 @@ static constexpr bool GetInteger(const char* name, int& offset, int& value, int
if (!IsDigit(temp)) { if (!IsDigit(temp)) {
return {}; return {};
} }
if (temp == '0') {
return {};
}
do { do {
value = value * 10 + (temp - '0'); value = value * 10 + (temp - '0');
if (value > max) { if (value > max) {
@ -634,47 +629,11 @@ static bool ParseTimeZoneBinary(TimeZoneRule& time_zone_rule, FileSys::VirtualFi
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
} }
const auto typesequiv = [](TimeZoneRule& rule, int a, int b) -> bool {
if (a < 0 || a >= rule.type_count || b < 0 || b >= rule.type_count) {
return {};
}
const struct TimeTypeInfo* ap = &rule.ttis[a];
const struct TimeTypeInfo* bp = &rule.ttis[b];
return (ap->gmt_offset == bp->gmt_offset && ap->is_dst == bp->is_dst &&
(std::strcmp(&rule.chars[ap->abbreviation_list_index],
&rule.chars[bp->abbreviation_list_index]) == 0));
};
if (time_zone_rule.type_count == 0) { if (time_zone_rule.type_count == 0) {
return {}; return {};
} }
if (time_zone_rule.time_count > 1) { if (time_zone_rule.time_count > 1) {
if (time_zone_rule.ats[0] <= std::numeric_limits<s64>::max() - seconds_per_repeat) { UNIMPLEMENTED();
s64 repeatat = time_zone_rule.ats[0] + seconds_per_repeat;
int repeatattype = time_zone_rule.types[0];
for (int i = 1; i < time_zone_rule.time_count; ++i) {
if (time_zone_rule.ats[i] == repeatat &&
typesequiv(time_zone_rule, time_zone_rule.types[i], repeatattype)) {
time_zone_rule.go_back = true;
break;
}
}
}
if (std::numeric_limits<s64>::min() + seconds_per_repeat <=
time_zone_rule.ats[time_zone_rule.time_count - 1]) {
s64 repeatat = time_zone_rule.ats[time_zone_rule.time_count - 1] - seconds_per_repeat;
int repeatattype = time_zone_rule.types[time_zone_rule.time_count - 1];
for (int i = time_zone_rule.time_count; i >= 0; --i) {
if (time_zone_rule.ats[i] == repeatat &&
typesequiv(time_zone_rule, time_zone_rule.types[i], repeatattype)) {
time_zone_rule.go_ahead = true;
break;
}
}
}
} }
s32 default_type{}; s32 default_type{};

View file

@ -144,7 +144,8 @@ void ConfigureSystem::ApplyConfiguration() {
if (ui->custom_rtc_checkbox->isChecked()) { if (ui->custom_rtc_checkbox->isChecked()) {
Settings::values.custom_rtc = ui->custom_rtc_edit->dateTime().toSecsSinceEpoch(); Settings::values.custom_rtc = ui->custom_rtc_edit->dateTime().toSecsSinceEpoch();
if (system.IsPoweredOn()) { if (system.IsPoweredOn()) {
const s64 posix_time{*Settings::values.custom_rtc}; const s64 posix_time{*Settings::values.custom_rtc +
Service::Time::TimeManager::GetExternalTimeZoneOffset()};
system.GetTimeManager().UpdateLocalSystemClockTime(posix_time); system.GetTimeManager().UpdateLocalSystemClockTime(posix_time);
} }
} else { } else {