summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-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
5 files changed, 91 insertions, 2 deletions
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}