diff options
| author | 2019-01-10 17:05:21 -0500 | |
|---|---|---|
| committer | 2019-01-10 17:05:21 -0500 | |
| commit | c9ef8b0af1a5908822ca0f3bb3b2238018a555e8 (patch) | |
| tree | 157da486e44b5f7083607159e1bb8bb3e4f20842 | |
| parent | Merge pull request #1939 from DarkLordZach/web-applet (diff) | |
| parent | settings: Fix comment structure (diff) | |
| download | yuzu-c9ef8b0af1a5908822ca0f3bb3b2238018a555e8.tar.gz yuzu-c9ef8b0af1a5908822ca0f3bb3b2238018a555e8.tar.xz yuzu-c9ef8b0af1a5908822ca0f3bb3b2238018a555e8.zip | |
Merge pull request #1959 from DarkLordZach/custom-rtc
settings: Add support for setting the RTC manually
| -rw-r--r-- | src/core/core.cpp | 6 | ||||
| -rw-r--r-- | src/core/hle/service/time/time.cpp | 16 | ||||
| -rw-r--r-- | src/core/settings.h | 6 | ||||
| -rw-r--r-- | src/yuzu/configuration/config.cpp | 17 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_system.cpp | 19 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_system.ui | 77 | ||||
| -rw-r--r-- | src/yuzu_cmd/config.cpp | 12 | ||||
| -rw-r--r-- | src/yuzu_cmd/default_ini.h | 6 |
8 files changed, 120 insertions, 39 deletions
diff --git a/src/core/core.cpp b/src/core/core.cpp index 715172771..31c590866 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -30,6 +30,7 @@ | |||
| 30 | #include "core/hle/service/sm/sm.h" | 30 | #include "core/hle/service/sm/sm.h" |
| 31 | #include "core/loader/loader.h" | 31 | #include "core/loader/loader.h" |
| 32 | #include "core/perf_stats.h" | 32 | #include "core/perf_stats.h" |
| 33 | #include "core/settings.h" | ||
| 33 | #include "core/telemetry_session.h" | 34 | #include "core/telemetry_session.h" |
| 34 | #include "frontend/applets/profile_select.h" | 35 | #include "frontend/applets/profile_select.h" |
| 35 | #include "frontend/applets/software_keyboard.h" | 36 | #include "frontend/applets/software_keyboard.h" |
| @@ -96,6 +97,11 @@ struct System::Impl { | |||
| 96 | CoreTiming::Init(); | 97 | CoreTiming::Init(); |
| 97 | kernel.Initialize(); | 98 | kernel.Initialize(); |
| 98 | 99 | ||
| 100 | const auto current_time = std::chrono::duration_cast<std::chrono::seconds>( | ||
| 101 | std::chrono::system_clock::now().time_since_epoch()); | ||
| 102 | Settings::values.custom_rtc_differential = | ||
| 103 | Settings::values.custom_rtc.value_or(current_time) - current_time; | ||
| 104 | |||
| 99 | // Create a default fs if one doesn't already exist. | 105 | // Create a default fs if one doesn't already exist. |
| 100 | if (virtual_filesystem == nullptr) | 106 | if (virtual_filesystem == nullptr) |
| 101 | virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>(); | 107 | virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>(); |
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp index 16564de24..c13640ad8 100644 --- a/src/core/hle/service/time/time.cpp +++ b/src/core/hle/service/time/time.cpp | |||
| @@ -12,9 +12,16 @@ | |||
| 12 | #include "core/hle/kernel/client_session.h" | 12 | #include "core/hle/kernel/client_session.h" |
| 13 | #include "core/hle/service/time/interface.h" | 13 | #include "core/hle/service/time/interface.h" |
| 14 | #include "core/hle/service/time/time.h" | 14 | #include "core/hle/service/time/time.h" |
| 15 | #include "core/settings.h" | ||
| 15 | 16 | ||
| 16 | namespace Service::Time { | 17 | namespace Service::Time { |
| 17 | 18 | ||
| 19 | static std::chrono::seconds GetSecondsSinceEpoch() { | ||
| 20 | return std::chrono::duration_cast<std::chrono::seconds>( | ||
| 21 | std::chrono::system_clock::now().time_since_epoch()) + | ||
| 22 | Settings::values.custom_rtc_differential; | ||
| 23 | } | ||
| 24 | |||
| 18 | static void PosixToCalendar(u64 posix_time, CalendarTime& calendar_time, | 25 | static void PosixToCalendar(u64 posix_time, CalendarTime& calendar_time, |
| 19 | CalendarAdditionalInfo& additional_info, | 26 | CalendarAdditionalInfo& additional_info, |
| 20 | [[maybe_unused]] const TimeZoneRule& /*rule*/) { | 27 | [[maybe_unused]] const TimeZoneRule& /*rule*/) { |
| @@ -68,9 +75,7 @@ public: | |||
| 68 | 75 | ||
| 69 | private: | 76 | private: |
| 70 | void GetCurrentTime(Kernel::HLERequestContext& ctx) { | 77 | void GetCurrentTime(Kernel::HLERequestContext& ctx) { |
| 71 | const s64 time_since_epoch{std::chrono::duration_cast<std::chrono::seconds>( | 78 | const s64 time_since_epoch{GetSecondsSinceEpoch().count()}; |
| 72 | std::chrono::system_clock::now().time_since_epoch()) | ||
| 73 | .count()}; | ||
| 74 | LOG_DEBUG(Service_Time, "called"); | 79 | LOG_DEBUG(Service_Time, "called"); |
| 75 | 80 | ||
| 76 | IPC::ResponseBuilder rb{ctx, 4}; | 81 | IPC::ResponseBuilder rb{ctx, 4}; |
| @@ -266,10 +271,7 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) { | |||
| 266 | IPC::RequestParser rp{ctx}; | 271 | IPC::RequestParser rp{ctx}; |
| 267 | const auto initial_type = rp.PopRaw<u8>(); | 272 | const auto initial_type = rp.PopRaw<u8>(); |
| 268 | 273 | ||
| 269 | const s64 time_since_epoch{std::chrono::duration_cast<std::chrono::seconds>( | 274 | const s64 time_since_epoch{GetSecondsSinceEpoch().count()}; |
| 270 | std::chrono::system_clock::now().time_since_epoch()) | ||
| 271 | .count()}; | ||
| 272 | |||
| 273 | const std::time_t time(time_since_epoch); | 275 | const std::time_t time(time_since_epoch); |
| 274 | const std::tm* tm = std::localtime(&time); | 276 | const std::tm* tm = std::localtime(&time); |
| 275 | if (tm == nullptr) { | 277 | if (tm == nullptr) { |
diff --git a/src/core/settings.h b/src/core/settings.h index de01b05c0..29ce98983 100644 --- a/src/core/settings.h +++ b/src/core/settings.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <atomic> | 8 | #include <atomic> |
| 9 | #include <chrono> | ||
| 9 | #include <map> | 10 | #include <map> |
| 10 | #include <optional> | 11 | #include <optional> |
| 11 | #include <string> | 12 | #include <string> |
| @@ -350,6 +351,11 @@ struct Values { | |||
| 350 | bool use_docked_mode; | 351 | bool use_docked_mode; |
| 351 | bool enable_nfc; | 352 | bool enable_nfc; |
| 352 | std::optional<u32> rng_seed; | 353 | std::optional<u32> rng_seed; |
| 354 | // Measured in seconds since epoch | ||
| 355 | std::optional<std::chrono::seconds> custom_rtc; | ||
| 356 | // Set on game boot, reset on stop. Seconds difference between current time and `custom_rtc` | ||
| 357 | std::chrono::seconds custom_rtc_differential; | ||
| 358 | |||
| 353 | s32 current_user; | 359 | s32 current_user; |
| 354 | s32 language_index; | 360 | s32 language_index; |
| 355 | 361 | ||
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 165d70e9c..ddf4cf552 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp | |||
| @@ -419,13 +419,21 @@ void Config::ReadValues() { | |||
| 419 | 419 | ||
| 420 | Settings::values.language_index = qt_config->value("language_index", 1).toInt(); | 420 | Settings::values.language_index = qt_config->value("language_index", 1).toInt(); |
| 421 | 421 | ||
| 422 | const auto enabled = qt_config->value("rng_seed_enabled", false).toBool(); | 422 | const auto rng_seed_enabled = qt_config->value("rng_seed_enabled", false).toBool(); |
| 423 | if (enabled) { | 423 | if (rng_seed_enabled) { |
| 424 | Settings::values.rng_seed = qt_config->value("rng_seed", 0).toULongLong(); | 424 | Settings::values.rng_seed = qt_config->value("rng_seed", 0).toULongLong(); |
| 425 | } else { | 425 | } else { |
| 426 | Settings::values.rng_seed = std::nullopt; | 426 | Settings::values.rng_seed = std::nullopt; |
| 427 | } | 427 | } |
| 428 | 428 | ||
| 429 | const auto custom_rtc_enabled = qt_config->value("custom_rtc_enabled", false).toBool(); | ||
| 430 | if (custom_rtc_enabled) { | ||
| 431 | Settings::values.custom_rtc = | ||
| 432 | std::chrono::seconds(qt_config->value("custom_rtc", 0).toULongLong()); | ||
| 433 | } else { | ||
| 434 | Settings::values.custom_rtc = std::nullopt; | ||
| 435 | } | ||
| 436 | |||
| 429 | qt_config->endGroup(); | 437 | qt_config->endGroup(); |
| 430 | 438 | ||
| 431 | qt_config->beginGroup("Miscellaneous"); | 439 | qt_config->beginGroup("Miscellaneous"); |
| @@ -653,6 +661,11 @@ void Config::SaveValues() { | |||
| 653 | qt_config->setValue("rng_seed_enabled", Settings::values.rng_seed.has_value()); | 661 | qt_config->setValue("rng_seed_enabled", Settings::values.rng_seed.has_value()); |
| 654 | qt_config->setValue("rng_seed", Settings::values.rng_seed.value_or(0)); | 662 | qt_config->setValue("rng_seed", Settings::values.rng_seed.value_or(0)); |
| 655 | 663 | ||
| 664 | qt_config->setValue("custom_rtc_enabled", Settings::values.custom_rtc.has_value()); | ||
| 665 | qt_config->setValue("custom_rtc", | ||
| 666 | QVariant::fromValue<long long>( | ||
| 667 | Settings::values.custom_rtc.value_or(std::chrono::seconds{}).count())); | ||
| 668 | |||
| 656 | qt_config->endGroup(); | 669 | qt_config->endGroup(); |
| 657 | 670 | ||
| 658 | qt_config->beginGroup("Miscellaneous"); | 671 | qt_config->beginGroup("Miscellaneous"); |
diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp index 445d01ca0..94e27349d 100644 --- a/src/yuzu/configuration/configure_system.cpp +++ b/src/yuzu/configuration/configure_system.cpp | |||
| @@ -51,6 +51,12 @@ ConfigureSystem::ConfigureSystem(QWidget* parent) : QWidget(parent), ui(new Ui:: | |||
| 51 | ui->rng_seed_edit->setText(QStringLiteral("00000000")); | 51 | ui->rng_seed_edit->setText(QStringLiteral("00000000")); |
| 52 | }); | 52 | }); |
| 53 | 53 | ||
| 54 | connect(ui->custom_rtc_checkbox, &QCheckBox::stateChanged, this, [this](bool checked) { | ||
| 55 | ui->custom_rtc_edit->setEnabled(checked); | ||
| 56 | if (!checked) | ||
| 57 | ui->custom_rtc_edit->setDateTime(QDateTime::currentDateTime()); | ||
| 58 | }); | ||
| 59 | |||
| 54 | this->setConfiguration(); | 60 | this->setConfiguration(); |
| 55 | } | 61 | } |
| 56 | 62 | ||
| @@ -67,6 +73,13 @@ void ConfigureSystem::setConfiguration() { | |||
| 67 | const auto rng_seed = | 73 | const auto rng_seed = |
| 68 | QString("%1").arg(Settings::values.rng_seed.value_or(0), 8, 16, QLatin1Char{'0'}).toUpper(); | 74 | QString("%1").arg(Settings::values.rng_seed.value_or(0), 8, 16, QLatin1Char{'0'}).toUpper(); |
| 69 | ui->rng_seed_edit->setText(rng_seed); | 75 | ui->rng_seed_edit->setText(rng_seed); |
| 76 | |||
| 77 | ui->custom_rtc_checkbox->setChecked(Settings::values.custom_rtc.has_value()); | ||
| 78 | ui->custom_rtc_edit->setEnabled(Settings::values.custom_rtc.has_value()); | ||
| 79 | |||
| 80 | const auto rtc_time = Settings::values.custom_rtc.value_or( | ||
| 81 | std::chrono::seconds(QDateTime::currentSecsSinceEpoch())); | ||
| 82 | ui->custom_rtc_edit->setDateTime(QDateTime::fromSecsSinceEpoch(rtc_time.count())); | ||
| 70 | } | 83 | } |
| 71 | 84 | ||
| 72 | void ConfigureSystem::ReadSystemSettings() {} | 85 | void ConfigureSystem::ReadSystemSettings() {} |
| @@ -82,6 +95,12 @@ void ConfigureSystem::applyConfiguration() { | |||
| 82 | else | 95 | else |
| 83 | Settings::values.rng_seed = std::nullopt; | 96 | Settings::values.rng_seed = std::nullopt; |
| 84 | 97 | ||
| 98 | if (ui->custom_rtc_checkbox->isChecked()) | ||
| 99 | Settings::values.custom_rtc = | ||
| 100 | std::chrono::seconds(ui->custom_rtc_edit->dateTime().toSecsSinceEpoch()); | ||
| 101 | else | ||
| 102 | Settings::values.custom_rtc = std::nullopt; | ||
| 103 | |||
| 85 | Settings::Apply(); | 104 | Settings::Apply(); |
| 86 | } | 105 | } |
| 87 | 106 | ||
diff --git a/src/yuzu/configuration/configure_system.ui b/src/yuzu/configuration/configure_system.ui index 74e800c2a..073327298 100644 --- a/src/yuzu/configuration/configure_system.ui +++ b/src/yuzu/configuration/configure_system.ui | |||
| @@ -22,6 +22,13 @@ | |||
| 22 | <string>System Settings</string> | 22 | <string>System Settings</string> |
| 23 | </property> | 23 | </property> |
| 24 | <layout class="QGridLayout" name="gridLayout"> | 24 | <layout class="QGridLayout" name="gridLayout"> |
| 25 | <item row="2" column="0"> | ||
| 26 | <widget class="QLabel" name="label_sound"> | ||
| 27 | <property name="text"> | ||
| 28 | <string>Sound output mode</string> | ||
| 29 | </property> | ||
| 30 | </widget> | ||
| 31 | </item> | ||
| 25 | <item row="1" column="1"> | 32 | <item row="1" column="1"> |
| 26 | <widget class="QComboBox" name="combo_language"> | 33 | <widget class="QComboBox" name="combo_language"> |
| 27 | <property name="toolTip"> | 34 | <property name="toolTip"> |
| @@ -114,27 +121,6 @@ | |||
| 114 | </item> | 121 | </item> |
| 115 | </widget> | 122 | </widget> |
| 116 | </item> | 123 | </item> |
| 117 | <item row="3" column="0"> | ||
| 118 | <widget class="QLabel" name="label_console_id"> | ||
| 119 | <property name="text"> | ||
| 120 | <string>Console ID:</string> | ||
| 121 | </property> | ||
| 122 | </widget> | ||
| 123 | </item> | ||
| 124 | <item row="2" column="0"> | ||
| 125 | <widget class="QLabel" name="label_sound"> | ||
| 126 | <property name="text"> | ||
| 127 | <string>Sound output mode</string> | ||
| 128 | </property> | ||
| 129 | </widget> | ||
| 130 | </item> | ||
| 131 | <item row="0" column="0"> | ||
| 132 | <widget class="QLabel" name="label_birthday"> | ||
| 133 | <property name="text"> | ||
| 134 | <string>Birthday</string> | ||
| 135 | </property> | ||
| 136 | </widget> | ||
| 137 | </item> | ||
| 138 | <item row="0" column="1"> | 124 | <item row="0" column="1"> |
| 139 | <layout class="QHBoxLayout" name="horizontalLayout_birthday2"> | 125 | <layout class="QHBoxLayout" name="horizontalLayout_birthday2"> |
| 140 | <item> | 126 | <item> |
| @@ -206,6 +192,20 @@ | |||
| 206 | </item> | 192 | </item> |
| 207 | </layout> | 193 | </layout> |
| 208 | </item> | 194 | </item> |
| 195 | <item row="3" column="0"> | ||
| 196 | <widget class="QLabel" name="label_console_id"> | ||
| 197 | <property name="text"> | ||
| 198 | <string>Console ID:</string> | ||
| 199 | </property> | ||
| 200 | </widget> | ||
| 201 | </item> | ||
| 202 | <item row="0" column="0"> | ||
| 203 | <widget class="QLabel" name="label_birthday"> | ||
| 204 | <property name="text"> | ||
| 205 | <string>Birthday</string> | ||
| 206 | </property> | ||
| 207 | </widget> | ||
| 208 | </item> | ||
| 209 | <item row="3" column="1"> | 209 | <item row="3" column="1"> |
| 210 | <widget class="QPushButton" name="button_regenerate_console_id"> | 210 | <widget class="QPushButton" name="button_regenerate_console_id"> |
| 211 | <property name="sizePolicy"> | 211 | <property name="sizePolicy"> |
| @@ -241,21 +241,21 @@ | |||
| 241 | </item> | 241 | </item> |
| 242 | </widget> | 242 | </widget> |
| 243 | </item> | 243 | </item> |
| 244 | <item row="1" column="0"> | 244 | <item row="5" column="0"> |
| 245 | <widget class="QLabel" name="label_language"> | 245 | <widget class="QCheckBox" name="rng_seed_checkbox"> |
| 246 | <property name="text"> | 246 | <property name="text"> |
| 247 | <string>Language</string> | 247 | <string>RNG Seed</string> |
| 248 | </property> | 248 | </property> |
| 249 | </widget> | 249 | </widget> |
| 250 | </item> | 250 | </item> |
| 251 | <item row="4" column="0"> | 251 | <item row="1" column="0"> |
| 252 | <widget class="QCheckBox" name="rng_seed_checkbox"> | 252 | <widget class="QLabel" name="label_language"> |
| 253 | <property name="text"> | 253 | <property name="text"> |
| 254 | <string>RNG Seed</string> | 254 | <string>Language</string> |
| 255 | </property> | 255 | </property> |
| 256 | </widget> | 256 | </widget> |
| 257 | </item> | 257 | </item> |
| 258 | <item row="4" column="1"> | 258 | <item row="5" column="1"> |
| 259 | <widget class="QLineEdit" name="rng_seed_edit"> | 259 | <widget class="QLineEdit" name="rng_seed_edit"> |
| 260 | <property name="sizePolicy"> | 260 | <property name="sizePolicy"> |
| 261 | <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> | 261 | <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> |
| @@ -276,6 +276,27 @@ | |||
| 276 | </property> | 276 | </property> |
| 277 | </widget> | 277 | </widget> |
| 278 | </item> | 278 | </item> |
| 279 | <item row="4" column="0"> | ||
| 280 | <widget class="QCheckBox" name="custom_rtc_checkbox"> | ||
| 281 | <property name="text"> | ||
| 282 | <string>Custom RTC</string> | ||
| 283 | </property> | ||
| 284 | </widget> | ||
| 285 | </item> | ||
| 286 | <item row="4" column="1"> | ||
| 287 | <widget class="QDateTimeEdit" name="custom_rtc_edit"> | ||
| 288 | <property name="minimumDate"> | ||
| 289 | <date> | ||
| 290 | <year>1970</year> | ||
| 291 | <month>1</month> | ||
| 292 | <day>1</day> | ||
| 293 | </date> | ||
| 294 | </property> | ||
| 295 | <property name="displayFormat"> | ||
| 296 | <string>d MMM yyyy h:mm:ss AP</string> | ||
| 297 | </property> | ||
| 298 | </widget> | ||
| 299 | </item> | ||
| 279 | </layout> | 300 | </layout> |
| 280 | </widget> | 301 | </widget> |
| 281 | </item> | 302 | </item> |
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp index fe0d1eebf..7a77f76e8 100644 --- a/src/yuzu_cmd/config.cpp +++ b/src/yuzu_cmd/config.cpp | |||
| @@ -325,13 +325,21 @@ void Config::ReadValues() { | |||
| 325 | Settings::values.current_user = std::clamp<int>( | 325 | Settings::values.current_user = std::clamp<int>( |
| 326 | sdl2_config->GetInteger("System", "current_user", 0), 0, Service::Account::MAX_USERS - 1); | 326 | sdl2_config->GetInteger("System", "current_user", 0), 0, Service::Account::MAX_USERS - 1); |
| 327 | 327 | ||
| 328 | const auto enabled = sdl2_config->GetBoolean("System", "rng_seed_enabled", false); | 328 | const auto rng_seed_enabled = sdl2_config->GetBoolean("System", "rng_seed_enabled", false); |
| 329 | if (enabled) { | 329 | if (rng_seed_enabled) { |
| 330 | Settings::values.rng_seed = sdl2_config->GetInteger("System", "rng_seed", 0); | 330 | Settings::values.rng_seed = sdl2_config->GetInteger("System", "rng_seed", 0); |
| 331 | } else { | 331 | } else { |
| 332 | Settings::values.rng_seed = std::nullopt; | 332 | Settings::values.rng_seed = std::nullopt; |
| 333 | } | 333 | } |
| 334 | 334 | ||
| 335 | const auto custom_rtc_enabled = sdl2_config->GetBoolean("System", "custom_rtc_enabled", false); | ||
| 336 | if (custom_rtc_enabled) { | ||
| 337 | Settings::values.custom_rtc = | ||
| 338 | std::chrono::seconds(sdl2_config->GetInteger("System", "custom_rtc", 0)); | ||
| 339 | } else { | ||
| 340 | Settings::values.custom_rtc = std::nullopt; | ||
| 341 | } | ||
| 342 | |||
| 335 | // Core | 343 | // Core |
| 336 | Settings::values.use_cpu_jit = sdl2_config->GetBoolean("Core", "use_cpu_jit", true); | 344 | Settings::values.use_cpu_jit = sdl2_config->GetBoolean("Core", "use_cpu_jit", true); |
| 337 | Settings::values.use_multi_core = sdl2_config->GetBoolean("Core", "use_multi_core", false); | 345 | Settings::values.use_multi_core = sdl2_config->GetBoolean("Core", "use_multi_core", false); |
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h index 0f3f8da50..ba51a4a51 100644 --- a/src/yuzu_cmd/default_ini.h +++ b/src/yuzu_cmd/default_ini.h | |||
| @@ -183,6 +183,12 @@ enable_nfc = | |||
| 183 | rng_seed_enabled = | 183 | rng_seed_enabled = |
| 184 | rng_seed = | 184 | rng_seed = |
| 185 | 185 | ||
| 186 | # Sets the current time (in seconds since 12:00 AM Jan 1, 1970) that will be used by the time service | ||
| 187 | # This will auto-increment, with the time set being the time the game is started | ||
| 188 | # This override will only occur if custom_rtc_enabled is true, otherwise the current time is used | ||
| 189 | custom_rtc_enabled = | ||
| 190 | custom_rtc = | ||
| 191 | |||
| 186 | # Sets the account username, max length is 32 characters | 192 | # Sets the account username, max length is 32 characters |
| 187 | # yuzu (default) | 193 | # yuzu (default) |
| 188 | username = yuzu | 194 | username = yuzu |