Config: auto-select region and language

This commit is contained in:
wwylele 2016-11-30 11:32:09 +02:00
parent 8d529a5cda
commit 84e78790ab
11 changed files with 108 additions and 7 deletions

View file

@ -114,6 +114,8 @@ static const std::vector<u8> cfg_system_savedata_id = {
0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x01, 0x00,
};
static u32 preferred_region_code = 0;
void GetCountryCodeString(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 country_code_id = cmd_buff[1];
@ -159,11 +161,18 @@ void GetCountryCodeID(Service::Interface* self) {
cmd_buff[2] = country_code_id;
}
static u32 GetRegionValue() {
if (Settings::values.region_value == Settings::REGION_VALUE_AUTO_SELECT)
return preferred_region_code;
return Settings::values.region_value;
}
void SecureInfoGetRegion(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[1] = RESULT_SUCCESS.raw;
cmd_buff[2] = Settings::values.region_value;
cmd_buff[2] = GetRegionValue();
}
void GenHashConsoleUnique(Service::Interface* self) {
@ -183,7 +192,7 @@ void GetRegionCanadaUSA(Service::Interface* self) {
cmd_buff[1] = RESULT_SUCCESS.raw;
u8 canada_or_usa = 1;
if (canada_or_usa == Settings::values.region_value) {
if (canada_or_usa == GetRegionValue()) {
cmd_buff[2] = 1;
} else {
cmd_buff[2] = 0;
@ -313,10 +322,47 @@ static ResultVal<void*> GetConfigInfoBlockPointer(u32 block_id, u32 size, u32 fl
return MakeResult<void*>(pointer);
}
/// Checks if the language is available in the chosen region, and returns a proper one
static u8 AdjustLanguageInfoBlock(u32 region, u8 language) {
static const std::array<std::vector<u8>, 7> region_languages{{
// JPN
{LANGUAGE_JP},
// USA
{LANGUAGE_EN, LANGUAGE_FR, LANGUAGE_ES, LANGUAGE_PT},
// EUR
{LANGUAGE_EN, LANGUAGE_FR, LANGUAGE_DE, LANGUAGE_IT, LANGUAGE_ES, LANGUAGE_NL, LANGUAGE_PT,
LANGUAGE_RU},
// AUS
{LANGUAGE_EN, LANGUAGE_FR, LANGUAGE_DE, LANGUAGE_IT, LANGUAGE_ES, LANGUAGE_NL, LANGUAGE_PT,
LANGUAGE_RU},
// CHN
{LANGUAGE_ZH},
// KOR
{LANGUAGE_KO},
// TWN
{LANGUAGE_TW},
}};
const auto& available = region_languages[region];
if (std::find(available.begin(), available.end(), language) == available.end()) {
return available[0];
}
return language;
}
ResultCode GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, void* output) {
void* pointer;
CASCADE_RESULT(pointer, GetConfigInfoBlockPointer(block_id, size, flag));
memcpy(output, pointer, size);
// override the language setting if the region setting is auto
if (block_id == LanguageBlockID &&
Settings::values.region_value == Settings::REGION_VALUE_AUTO_SELECT) {
u8 language;
memcpy(&language, output, sizeof(u8));
language = AdjustLanguageInfoBlock(preferred_region_code, language);
memcpy(output, &language, sizeof(u8));
}
return RESULT_SUCCESS;
}
@ -533,10 +579,17 @@ void Init() {
AddService(new CFG_U_Interface);
LoadConfigNANDSaveFile();
preferred_region_code = 0;
}
void Shutdown() {}
void SetPreferredRegionCode(u32 region_code) {
preferred_region_code = region_code;
LOG_INFO(Service_CFG, "Preferred region code set to %u", preferred_region_code);
}
void SetUsername(const std::u16string& name) {
ASSERT(name.size() <= 10);
UsernameBlock block{};

View file

@ -282,6 +282,13 @@ void Init();
/// Shutdown the config service
void Shutdown();
/**
* Set the region code preferred by the game so that CFG will adjust to it when the region setting
* is auto.
* @param region_code the preferred region code to set
*/
void SetPreferredRegionCode(u32 region_code);
// Utilities for frontend to set config data.
// Note: before calling these functions, LoadConfigNANDSaveFile should be called,
// and UpdateConfigNANDSavegame should be called after making changes to config data.

View file

@ -11,8 +11,10 @@
#include "core/file_sys/archive_romfs.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/resource_limit.h"
#include "core/hle/service/cfg/cfg.h"
#include "core/hle/service/fs/archive.h"
#include "core/loader/ncch.h"
#include "core/loader/smdh.h"
#include "core/memory.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
@ -309,6 +311,23 @@ ResultStatus AppLoader_NCCH::LoadExeFS() {
return ResultStatus::Success;
}
void AppLoader_NCCH::ParseRegionLockoutInfo() {
std::vector<u8> smdh_buffer;
if (ReadIcon(smdh_buffer) == ResultStatus::Success && smdh_buffer.size() >= sizeof(SMDH)) {
SMDH smdh;
memcpy(&smdh, smdh_buffer.data(), sizeof(SMDH));
u32 region_lockout = smdh.region_lockout;
constexpr u32 REGION_COUNT = 7;
for (u32 region = 0; region < REGION_COUNT; ++region) {
if (region_lockout & 1) {
Service::CFG::SetPreferredRegionCode(region);
break;
}
region_lockout >>= 1;
}
}
}
ResultStatus AppLoader_NCCH::Load() {
if (is_loaded)
return ResultStatus::ErrorAlreadyLoaded;
@ -325,6 +344,9 @@ ResultStatus AppLoader_NCCH::Load() {
Service::FS::RegisterArchiveType(std::make_unique<FileSys::ArchiveFactory_RomFS>(*this),
Service::FS::ArchiveIdCode::RomFS);
ParseRegionLockoutInfo();
return ResultStatus::Success;
}

View file

@ -250,6 +250,9 @@ private:
*/
ResultStatus LoadExeFS();
/// Reads the region lockout info in the SMDH and send it to CFG service
void ParseRegionLockoutInfo();
bool is_exefs_loaded = false;
bool is_compressed = false;

View file

@ -110,5 +110,9 @@ struct Values {
u16 gdbstub_port;
} extern values;
// a special value for Values::region_value indicating that citra will automatically select a region
// value to fit the region lockout info of the game
static constexpr int REGION_VALUE_AUTO_SELECT = -1;
void Apply();
}