summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/citra/config.cpp3
-rw-r--r--src/citra/default_ini.h2
-rw-r--r--src/citra_qt/config.cpp3
-rw-r--r--src/citra_qt/configure_general.cpp6
-rw-r--r--src/citra_qt/configure_general.ui5
-rw-r--r--src/citra_qt/configure_system.ui3
-rw-r--r--src/core/hle/service/cfg/cfg.cpp57
-rw-r--r--src/core/hle/service/cfg/cfg.h7
-rw-r--r--src/core/loader/ncch.cpp22
-rw-r--r--src/core/loader/ncch.h3
-rw-r--r--src/core/settings.h4
11 files changed, 108 insertions, 7 deletions
diff --git a/src/citra/config.cpp b/src/citra/config.cpp
index 29462c982..98f093258 100644
--- a/src/citra/config.cpp
+++ b/src/citra/config.cpp
@@ -89,7 +89,8 @@ void Config::ReadValues() {
89 89
90 // System 90 // System
91 Settings::values.is_new_3ds = sdl2_config->GetBoolean("System", "is_new_3ds", false); 91 Settings::values.is_new_3ds = sdl2_config->GetBoolean("System", "is_new_3ds", false);
92 Settings::values.region_value = sdl2_config->GetInteger("System", "region_value", 1); 92 Settings::values.region_value =
93 sdl2_config->GetInteger("System", "region_value", Settings::REGION_VALUE_AUTO_SELECT);
93 94
94 // Miscellaneous 95 // Miscellaneous
95 Settings::values.log_filter = sdl2_config->Get("Miscellaneous", "log_filter", "*:Info"); 96 Settings::values.log_filter = sdl2_config->Get("Miscellaneous", "log_filter", "*:Info");
diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h
index 001b18ac2..50c4a2812 100644
--- a/src/citra/default_ini.h
+++ b/src/citra/default_ini.h
@@ -101,7 +101,7 @@ use_virtual_sd =
101is_new_3ds = 101is_new_3ds =
102 102
103# The system region that Citra will use during emulation 103# The system region that Citra will use during emulation
104# 0: Japan, 1: USA (default), 2: Europe, 3: Australia, 4: China, 5: Korea, 6: Taiwan 104# -1: Auto-select (default), 0: Japan, 1: USA, 2: Europe, 3: Australia, 4: China, 5: Korea, 6: Taiwan
105region_value = 105region_value =
106 106
107[Miscellaneous] 107[Miscellaneous]
diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp
index 06a4e9d25..c904c4b00 100644
--- a/src/citra_qt/config.cpp
+++ b/src/citra_qt/config.cpp
@@ -72,7 +72,8 @@ void Config::ReadValues() {
72 72
73 qt_config->beginGroup("System"); 73 qt_config->beginGroup("System");
74 Settings::values.is_new_3ds = qt_config->value("is_new_3ds", false).toBool(); 74 Settings::values.is_new_3ds = qt_config->value("is_new_3ds", false).toBool();
75 Settings::values.region_value = qt_config->value("region_value", 1).toInt(); 75 Settings::values.region_value =
76 qt_config->value("region_value", Settings::REGION_VALUE_AUTO_SELECT).toInt();
76 qt_config->endGroup(); 77 qt_config->endGroup();
77 78
78 qt_config->beginGroup("Miscellaneous"); 79 qt_config->beginGroup("Miscellaneous");
diff --git a/src/citra_qt/configure_general.cpp b/src/citra_qt/configure_general.cpp
index 03cd8835b..ac90a6df4 100644
--- a/src/citra_qt/configure_general.cpp
+++ b/src/citra_qt/configure_general.cpp
@@ -23,13 +23,15 @@ void ConfigureGeneral::setConfiguration() {
23 ui->toggle_deepscan->setChecked(UISettings::values.gamedir_deepscan); 23 ui->toggle_deepscan->setChecked(UISettings::values.gamedir_deepscan);
24 ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing); 24 ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing);
25 ui->toggle_cpu_jit->setChecked(Settings::values.use_cpu_jit); 25 ui->toggle_cpu_jit->setChecked(Settings::values.use_cpu_jit);
26 ui->region_combobox->setCurrentIndex(Settings::values.region_value); 26
27 // The first item is "auto-select" with actual value -1, so plus one here will do the trick
28 ui->region_combobox->setCurrentIndex(Settings::values.region_value + 1);
27} 29}
28 30
29void ConfigureGeneral::applyConfiguration() { 31void ConfigureGeneral::applyConfiguration() {
30 UISettings::values.gamedir_deepscan = ui->toggle_deepscan->isChecked(); 32 UISettings::values.gamedir_deepscan = ui->toggle_deepscan->isChecked();
31 UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked(); 33 UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked();
32 Settings::values.region_value = ui->region_combobox->currentIndex(); 34 Settings::values.region_value = ui->region_combobox->currentIndex() - 1;
33 Settings::values.use_cpu_jit = ui->toggle_cpu_jit->isChecked(); 35 Settings::values.use_cpu_jit = ui->toggle_cpu_jit->isChecked();
34 Settings::Apply(); 36 Settings::Apply();
35} 37}
diff --git a/src/citra_qt/configure_general.ui b/src/citra_qt/configure_general.ui
index 81688113f..342954e41 100644
--- a/src/citra_qt/configure_general.ui
+++ b/src/citra_qt/configure_general.ui
@@ -84,6 +84,11 @@
84 <widget class="QComboBox" name="region_combobox"> 84 <widget class="QComboBox" name="region_combobox">
85 <item> 85 <item>
86 <property name="text"> 86 <property name="text">
87 <string>Auto-select</string>
88 </property>
89 </item>
90 <item>
91 <property name="text">
87 <string notr="true">JPN</string> 92 <string notr="true">JPN</string>
88 </property> 93 </property>
89 </item> 94 </item>
diff --git a/src/citra_qt/configure_system.ui b/src/citra_qt/configure_system.ui
index 6a906b61b..cc54fa37f 100644
--- a/src/citra_qt/configure_system.ui
+++ b/src/citra_qt/configure_system.ui
@@ -129,6 +129,9 @@
129 </item> 129 </item>
130 <item row="2" column="1"> 130 <item row="2" column="1">
131 <widget class="QComboBox" name="combo_language"> 131 <widget class="QComboBox" name="combo_language">
132 <property name="toolTip">
133 <string>Note: this can be overridden when region setting is auto-select</string>
134 </property>
132 <item> 135 <item>
133 <property name="text"> 136 <property name="text">
134 <string>Japanese (日本語)</string> 137 <string>Japanese (日本語)</string>
diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp
index 65655f45d..0bf59eb76 100644
--- a/src/core/hle/service/cfg/cfg.cpp
+++ b/src/core/hle/service/cfg/cfg.cpp
@@ -115,6 +115,8 @@ static const std::vector<u8> cfg_system_savedata_id = {
115 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x01, 0x00, 115 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x01, 0x00,
116}; 116};
117 117
118static u32 preferred_region_code = 0;
119
118void GetCountryCodeString(Service::Interface* self) { 120void GetCountryCodeString(Service::Interface* self) {
119 u32* cmd_buff = Kernel::GetCommandBuffer(); 121 u32* cmd_buff = Kernel::GetCommandBuffer();
120 u32 country_code_id = cmd_buff[1]; 122 u32 country_code_id = cmd_buff[1];
@@ -160,11 +162,18 @@ void GetCountryCodeID(Service::Interface* self) {
160 cmd_buff[2] = country_code_id; 162 cmd_buff[2] = country_code_id;
161} 163}
162 164
165static u32 GetRegionValue() {
166 if (Settings::values.region_value == Settings::REGION_VALUE_AUTO_SELECT)
167 return preferred_region_code;
168
169 return Settings::values.region_value;
170}
171
163void SecureInfoGetRegion(Service::Interface* self) { 172void SecureInfoGetRegion(Service::Interface* self) {
164 u32* cmd_buff = Kernel::GetCommandBuffer(); 173 u32* cmd_buff = Kernel::GetCommandBuffer();
165 174
166 cmd_buff[1] = RESULT_SUCCESS.raw; 175 cmd_buff[1] = RESULT_SUCCESS.raw;
167 cmd_buff[2] = Settings::values.region_value; 176 cmd_buff[2] = GetRegionValue();
168} 177}
169 178
170void GenHashConsoleUnique(Service::Interface* self) { 179void GenHashConsoleUnique(Service::Interface* self) {
@@ -184,7 +193,7 @@ void GetRegionCanadaUSA(Service::Interface* self) {
184 cmd_buff[1] = RESULT_SUCCESS.raw; 193 cmd_buff[1] = RESULT_SUCCESS.raw;
185 194
186 u8 canada_or_usa = 1; 195 u8 canada_or_usa = 1;
187 if (canada_or_usa == Settings::values.region_value) { 196 if (canada_or_usa == GetRegionValue()) {
188 cmd_buff[2] = 1; 197 cmd_buff[2] = 1;
189 } else { 198 } else {
190 cmd_buff[2] = 0; 199 cmd_buff[2] = 0;
@@ -314,10 +323,47 @@ static ResultVal<void*> GetConfigInfoBlockPointer(u32 block_id, u32 size, u32 fl
314 return MakeResult<void*>(pointer); 323 return MakeResult<void*>(pointer);
315} 324}
316 325
326/// Checks if the language is available in the chosen region, and returns a proper one
327static u8 AdjustLanguageInfoBlock(u32 region, u8 language) {
328 static const std::array<std::vector<u8>, 7> region_languages{{
329 // JPN
330 {LANGUAGE_JP},
331 // USA
332 {LANGUAGE_EN, LANGUAGE_FR, LANGUAGE_ES, LANGUAGE_PT},
333 // EUR
334 {LANGUAGE_EN, LANGUAGE_FR, LANGUAGE_DE, LANGUAGE_IT, LANGUAGE_ES, LANGUAGE_NL, LANGUAGE_PT,
335 LANGUAGE_RU},
336 // AUS
337 {LANGUAGE_EN, LANGUAGE_FR, LANGUAGE_DE, LANGUAGE_IT, LANGUAGE_ES, LANGUAGE_NL, LANGUAGE_PT,
338 LANGUAGE_RU},
339 // CHN
340 {LANGUAGE_ZH},
341 // KOR
342 {LANGUAGE_KO},
343 // TWN
344 {LANGUAGE_TW},
345 }};
346 const auto& available = region_languages[region];
347 if (std::find(available.begin(), available.end(), language) == available.end()) {
348 return available[0];
349 }
350 return language;
351}
352
317ResultCode GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, void* output) { 353ResultCode GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, void* output) {
318 void* pointer; 354 void* pointer;
319 CASCADE_RESULT(pointer, GetConfigInfoBlockPointer(block_id, size, flag)); 355 CASCADE_RESULT(pointer, GetConfigInfoBlockPointer(block_id, size, flag));
320 memcpy(output, pointer, size); 356 memcpy(output, pointer, size);
357
358 // override the language setting if the region setting is auto
359 if (block_id == LanguageBlockID &&
360 Settings::values.region_value == Settings::REGION_VALUE_AUTO_SELECT) {
361 u8 language;
362 memcpy(&language, output, sizeof(u8));
363 language = AdjustLanguageInfoBlock(preferred_region_code, language);
364 memcpy(output, &language, sizeof(u8));
365 }
366
321 return RESULT_SUCCESS; 367 return RESULT_SUCCESS;
322} 368}
323 369
@@ -535,10 +581,17 @@ void Init() {
535 AddService(new CFG_U); 581 AddService(new CFG_U);
536 582
537 LoadConfigNANDSaveFile(); 583 LoadConfigNANDSaveFile();
584
585 preferred_region_code = 0;
538} 586}
539 587
540void Shutdown() {} 588void Shutdown() {}
541 589
590void SetPreferredRegionCode(u32 region_code) {
591 preferred_region_code = region_code;
592 LOG_INFO(Service_CFG, "Preferred region code set to %u", preferred_region_code);
593}
594
542void SetUsername(const std::u16string& name) { 595void SetUsername(const std::u16string& name) {
543 ASSERT(name.size() <= 10); 596 ASSERT(name.size() <= 10);
544 UsernameBlock block{}; 597 UsernameBlock block{};
diff --git a/src/core/hle/service/cfg/cfg.h b/src/core/hle/service/cfg/cfg.h
index fb47c2aa5..618c9647e 100644
--- a/src/core/hle/service/cfg/cfg.h
+++ b/src/core/hle/service/cfg/cfg.h
@@ -282,6 +282,13 @@ void Init();
282/// Shutdown the config service 282/// Shutdown the config service
283void Shutdown(); 283void Shutdown();
284 284
285/**
286 * Set the region code preferred by the game so that CFG will adjust to it when the region setting
287 * is auto.
288 * @param region_code the preferred region code to set
289 */
290void SetPreferredRegionCode(u32 region_code);
291
285// Utilities for frontend to set config data. 292// Utilities for frontend to set config data.
286// Note: before calling these functions, LoadConfigNANDSaveFile should be called, 293// Note: before calling these functions, LoadConfigNANDSaveFile should be called,
287// and UpdateConfigNANDSavegame should be called after making changes to config data. 294// and UpdateConfigNANDSavegame should be called after making changes to config data.
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp
index 6f2164428..a204dc336 100644
--- a/src/core/loader/ncch.cpp
+++ b/src/core/loader/ncch.cpp
@@ -11,8 +11,10 @@
11#include "core/file_sys/archive_romfs.h" 11#include "core/file_sys/archive_romfs.h"
12#include "core/hle/kernel/process.h" 12#include "core/hle/kernel/process.h"
13#include "core/hle/kernel/resource_limit.h" 13#include "core/hle/kernel/resource_limit.h"
14#include "core/hle/service/cfg/cfg.h"
14#include "core/hle/service/fs/archive.h" 15#include "core/hle/service/fs/archive.h"
15#include "core/loader/ncch.h" 16#include "core/loader/ncch.h"
17#include "core/loader/smdh.h"
16#include "core/memory.h" 18#include "core/memory.h"
17 19
18//////////////////////////////////////////////////////////////////////////////////////////////////// 20////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -309,6 +311,23 @@ ResultStatus AppLoader_NCCH::LoadExeFS() {
309 return ResultStatus::Success; 311 return ResultStatus::Success;
310} 312}
311 313
314void AppLoader_NCCH::ParseRegionLockoutInfo() {
315 std::vector<u8> smdh_buffer;
316 if (ReadIcon(smdh_buffer) == ResultStatus::Success && smdh_buffer.size() >= sizeof(SMDH)) {
317 SMDH smdh;
318 memcpy(&smdh, smdh_buffer.data(), sizeof(SMDH));
319 u32 region_lockout = smdh.region_lockout;
320 constexpr u32 REGION_COUNT = 7;
321 for (u32 region = 0; region < REGION_COUNT; ++region) {
322 if (region_lockout & 1) {
323 Service::CFG::SetPreferredRegionCode(region);
324 break;
325 }
326 region_lockout >>= 1;
327 }
328 }
329}
330
312ResultStatus AppLoader_NCCH::Load() { 331ResultStatus AppLoader_NCCH::Load() {
313 if (is_loaded) 332 if (is_loaded)
314 return ResultStatus::ErrorAlreadyLoaded; 333 return ResultStatus::ErrorAlreadyLoaded;
@@ -325,6 +344,9 @@ ResultStatus AppLoader_NCCH::Load() {
325 344
326 Service::FS::RegisterArchiveType(std::make_unique<FileSys::ArchiveFactory_RomFS>(*this), 345 Service::FS::RegisterArchiveType(std::make_unique<FileSys::ArchiveFactory_RomFS>(*this),
327 Service::FS::ArchiveIdCode::RomFS); 346 Service::FS::ArchiveIdCode::RomFS);
347
348 ParseRegionLockoutInfo();
349
328 return ResultStatus::Success; 350 return ResultStatus::Success;
329} 351}
330 352
diff --git a/src/core/loader/ncch.h b/src/core/loader/ncch.h
index 6afc171a5..fe08f5b45 100644
--- a/src/core/loader/ncch.h
+++ b/src/core/loader/ncch.h
@@ -229,6 +229,9 @@ private:
229 */ 229 */
230 ResultStatus LoadExeFS(); 230 ResultStatus LoadExeFS();
231 231
232 /// Reads the region lockout info in the SMDH and send it to CFG service
233 void ParseRegionLockoutInfo();
234
232 bool is_exefs_loaded = false; 235 bool is_exefs_loaded = false;
233 bool is_compressed = false; 236 bool is_compressed = false;
234 237
diff --git a/src/core/settings.h b/src/core/settings.h
index db4c8fada..4e7a4b1be 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -110,5 +110,9 @@ struct Values {
110 u16 gdbstub_port; 110 u16 gdbstub_port;
111} extern values; 111} extern values;
112 112
113// a special value for Values::region_value indicating that citra will automatically select a region
114// value to fit the region lockout info of the game
115static constexpr int REGION_VALUE_AUTO_SELECT = -1;
116
113void Apply(); 117void Apply();
114} 118}