mirror of
https://github.com/azahar-emu/azahar
synced 2025-11-06 15:09:58 +01:00
Check that the country setting is valid for selected region (#847)
* Check that the country setting is valid for selected region * `SystemSaveGame.checkCountryCompatibility` -> `SystemSaveGame.getCountryCompatibility` * SettingsFragmentPresenter.kt: Moved `checkCountryCompatibility` definition out of `addSystemSettings` * SettingsFragmentPresenter.kt: Renamed `compat` value to `compatFlags` for better readability * configure_system.ui: Corrected indentation --------- Co-authored-by: OpenSauce04 <opensauce04@gmail.com>
This commit is contained in:
parent
eda2d6f9fa
commit
5c7622100b
@ -73,7 +73,7 @@ import kotlin.math.roundToInt
|
||||
|
||||
class SettingsAdapter(
|
||||
private val fragmentView: SettingsFragmentView,
|
||||
private val context: Context
|
||||
public val context: Context
|
||||
) : RecyclerView.Adapter<SettingViewHolder?>(), DialogInterface.OnClickListener {
|
||||
private var settings: ArrayList<SettingsItem>? = null
|
||||
private var clickedItem: SettingsItem? = null
|
||||
|
||||
@ -13,6 +13,7 @@ import android.hardware.camera2.CameraManager
|
||||
import android.os.Build
|
||||
import android.text.TextUtils
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import kotlin.math.min
|
||||
import org.citra.citra_emu.CitraApplication
|
||||
import org.citra.citra_emu.R
|
||||
@ -239,6 +240,30 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
|
||||
}
|
||||
}
|
||||
|
||||
private var countryCompatibilityChanged = true
|
||||
|
||||
private fun checkCountryCompatibility() {
|
||||
if (countryCompatibilityChanged) {
|
||||
countryCompatibilityChanged = false
|
||||
val compatFlags = SystemSaveGame.getCountryCompatibility(IntSetting.EMULATED_REGION.int)
|
||||
if (compatFlags != 0) {
|
||||
var message = ""
|
||||
if (compatFlags and 1 != 0) {
|
||||
message += settingsAdapter.context.getString(R.string.region_mismatch_emulated)
|
||||
}
|
||||
if (compatFlags and 2 != 0) {
|
||||
if (message.isNotEmpty()) message += "\n\n"
|
||||
message += settingsAdapter.context.getString(R.string.region_mismatch_console)
|
||||
}
|
||||
MaterialAlertDialogBuilder(settingsAdapter.context)
|
||||
.setTitle(R.string.region_mismatch)
|
||||
.setMessage(message)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
private fun addSystemSettings(sl: ArrayList<SettingsItem>) {
|
||||
settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.preferences_system))
|
||||
@ -282,51 +307,45 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
|
||||
)
|
||||
)
|
||||
add(HeaderSetting(R.string.profile_settings))
|
||||
add(
|
||||
StringInputSetting(
|
||||
usernameSetting,
|
||||
R.string.username,
|
||||
0,
|
||||
"AZAHAR",
|
||||
10
|
||||
)
|
||||
)
|
||||
val regionSetting = object : AbstractIntSetting {
|
||||
override var int: Int
|
||||
get() {
|
||||
val ret = IntSetting.EMULATED_REGION.int
|
||||
checkCountryCompatibility()
|
||||
return ret
|
||||
}
|
||||
set(value) {
|
||||
IntSetting.EMULATED_REGION.int = value
|
||||
countryCompatibilityChanged = true
|
||||
checkCountryCompatibility()
|
||||
}
|
||||
override val key = IntSetting.EMULATED_REGION.key
|
||||
override val section = null
|
||||
override val isRuntimeEditable = false
|
||||
override val valueAsString get() = int.toString()
|
||||
override val defaultValue = IntSetting.EMULATED_REGION.defaultValue
|
||||
}
|
||||
add(
|
||||
SingleChoiceSetting(
|
||||
IntSetting.EMULATED_REGION,
|
||||
regionSetting,
|
||||
R.string.emulated_region,
|
||||
0,
|
||||
R.array.regionNames,
|
||||
R.array.regionValues,
|
||||
IntSetting.EMULATED_REGION.key,
|
||||
IntSetting.EMULATED_REGION.defaultValue
|
||||
)
|
||||
)
|
||||
|
||||
val systemLanguageSetting = object : AbstractIntSetting {
|
||||
override var int: Int
|
||||
get() = SystemSaveGame.getSystemLanguage()
|
||||
set(value) = SystemSaveGame.setSystemLanguage(value)
|
||||
override val key = null
|
||||
override val section = null
|
||||
override val isRuntimeEditable = false
|
||||
override val valueAsString get() = int.toString()
|
||||
override val defaultValue = 1
|
||||
}
|
||||
add(
|
||||
SingleChoiceSetting(
|
||||
systemLanguageSetting,
|
||||
R.string.emulated_language,
|
||||
0,
|
||||
R.array.languageNames,
|
||||
R.array.languageValues
|
||||
)
|
||||
)
|
||||
|
||||
val systemCountrySetting = object : AbstractShortSetting {
|
||||
override var short: Short
|
||||
get() = SystemSaveGame.getCountryCode()
|
||||
set(value) = SystemSaveGame.setCountryCode(value)
|
||||
get() {
|
||||
val ret = SystemSaveGame.getCountryCode()
|
||||
checkCountryCompatibility()
|
||||
return ret;
|
||||
}
|
||||
set(value) {
|
||||
SystemSaveGame.setCountryCode(value)
|
||||
countryCompatibilityChanged = true
|
||||
checkCountryCompatibility()
|
||||
}
|
||||
override val key = null
|
||||
override val section = null
|
||||
override val isRuntimeEditable = false
|
||||
@ -348,7 +367,34 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
|
||||
countries.map { it.second }.toTypedArray()
|
||||
)
|
||||
)
|
||||
|
||||
val systemLanguageSetting = object : AbstractIntSetting {
|
||||
override var int: Int
|
||||
get() = SystemSaveGame.getSystemLanguage()
|
||||
set(value) = SystemSaveGame.setSystemLanguage(value)
|
||||
override val key = null
|
||||
override val section = null
|
||||
override val isRuntimeEditable = false
|
||||
override val valueAsString get() = int.toString()
|
||||
override val defaultValue = 1
|
||||
}
|
||||
add(
|
||||
SingleChoiceSetting(
|
||||
systemLanguageSetting,
|
||||
R.string.emulated_language,
|
||||
0,
|
||||
R.array.languageNames,
|
||||
R.array.languageValues
|
||||
)
|
||||
)
|
||||
add(
|
||||
StringInputSetting(
|
||||
usernameSetting,
|
||||
R.string.username,
|
||||
0,
|
||||
"AZAHAR",
|
||||
10
|
||||
)
|
||||
)
|
||||
val playCoinSettings = object : AbstractIntSetting {
|
||||
override var int: Int
|
||||
get() = SystemSaveGame.getPlayCoins()
|
||||
|
||||
@ -48,6 +48,8 @@ object SystemSaveGame {
|
||||
external fun getMac(): String
|
||||
|
||||
external fun regenerateMac()
|
||||
|
||||
external fun getCountryCompatibility(region: Int): Int
|
||||
}
|
||||
|
||||
enum class BirthdayMonth(val code: Int, val days: Int) {
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
#include <core/core.h>
|
||||
#include <core/hle/service/cfg/cfg.h>
|
||||
#include <core/hle/service/ptm/ptm.h>
|
||||
#include <core/hw/unique_data.h>
|
||||
#include "android_common/android_common.h"
|
||||
|
||||
static bool changes_pending = false;
|
||||
@ -138,4 +139,21 @@ void Java_org_citra_citra_1emu_utils_SystemSaveGame_regenerateMac(JNIEnv* env,
|
||||
cfg->SaveMacAddress();
|
||||
}
|
||||
|
||||
jint Java_org_citra_citra_1emu_utils_SystemSaveGame_getCountryCompatibility(
|
||||
JNIEnv* env, [[maybe_unused]] jobject obj, jint region) {
|
||||
int res = 0;
|
||||
u8 country = cfg->GetCountryCode();
|
||||
if (region != Settings::REGION_VALUE_AUTO_SELECT &&
|
||||
!Service::CFG::Module::IsValidRegionCountry(static_cast<u32>(region), country)) {
|
||||
res |= 1;
|
||||
}
|
||||
if (HW::UniqueData::GetSecureInfoA().IsValid()) {
|
||||
region = static_cast<jint>(cfg->GetRegionValue(true));
|
||||
if (!Service::CFG::Module::IsValidRegionCountry(static_cast<u32>(region), country)) {
|
||||
res |= 2;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
@ -200,6 +200,9 @@
|
||||
<string name="plugin_loader_description">Loads 3GX plugins from the emulated SD card if they are available.</string>
|
||||
<string name="allow_plugin_loader">Allow Applications to Change Plugin Loader State</string>
|
||||
<string name="allow_plugin_loader_description">Allows homebrew apps to enable the plugin loader even when it is disabled.</string>
|
||||
<string name="region_mismatch">Region Mismatch Warning</string>
|
||||
<string name="region_mismatch_emulated">The country setting is not valid for the selected emulated region.</string>
|
||||
<string name="region_mismatch_console">The country setting is not valid for the current linked console.</string>
|
||||
|
||||
<!-- Camera settings strings -->
|
||||
<string name="inner_camera">Inner Camera</string>
|
||||
|
||||
@ -121,16 +121,6 @@ void ConfigureGeneral::SetConfiguration() {
|
||||
!UISettings::values.screenshot_path.UsingGlobal());
|
||||
ConfigurationShared::SetHighlight(ui->emulation_speed_layout,
|
||||
!Settings::values.frame_limit.UsingGlobal());
|
||||
ConfigurationShared::SetHighlight(ui->widget_region,
|
||||
!Settings::values.region_value.UsingGlobal());
|
||||
const bool is_region_global = Settings::values.region_value.UsingGlobal();
|
||||
ui->region_combobox->setCurrentIndex(
|
||||
is_region_global ? ConfigurationShared::USE_GLOBAL_INDEX
|
||||
: static_cast<int>(Settings::values.region_value.GetValue()) +
|
||||
ConfigurationShared::USE_GLOBAL_OFFSET + 1);
|
||||
} else {
|
||||
// The first item is "auto-select" with actual value -1, so plus one here will do the trick
|
||||
ui->region_combobox->setCurrentIndex(Settings::values.region_value.GetValue() + 1);
|
||||
}
|
||||
|
||||
UISettings::values.screenshot_path.SetGlobal(ui->screenshot_combo->currentIndex() ==
|
||||
@ -160,9 +150,6 @@ void ConfigureGeneral::ResetDefaults() {
|
||||
}
|
||||
|
||||
void ConfigureGeneral::ApplyConfiguration() {
|
||||
ConfigurationShared::ApplyPerGameSetting(&Settings::values.region_value, ui->region_combobox,
|
||||
[](s32 index) { return index - 1; });
|
||||
|
||||
ConfigurationShared::ApplyPerGameSetting(
|
||||
&Settings::values.frame_limit, ui->emulation_speed_combo, [this](s32) {
|
||||
const bool is_maximum = ui->frame_limit->value() == ui->frame_limit->maximum();
|
||||
@ -191,7 +178,6 @@ void ConfigureGeneral::RetranslateUI() {
|
||||
|
||||
void ConfigureGeneral::SetupPerGameUI() {
|
||||
if (Settings::IsConfiguringGlobal()) {
|
||||
ui->region_combobox->setEnabled(Settings::values.region_value.UsingGlobal());
|
||||
ui->frame_limit->setEnabled(Settings::values.frame_limit.UsingGlobal());
|
||||
return;
|
||||
}
|
||||
@ -212,8 +198,4 @@ void ConfigureGeneral::SetupPerGameUI() {
|
||||
ui->button_reset_defaults->setVisible(false);
|
||||
ui->toggle_gamemode->setVisible(false);
|
||||
ui->toggle_update_checker->setVisible(false);
|
||||
|
||||
ConfigurationShared::SetColoredComboBox(
|
||||
ui->region_combobox, ui->widget_region,
|
||||
static_cast<u32>(Settings::values.region_value.GetValue(true) + 1));
|
||||
}
|
||||
|
||||
@ -73,75 +73,6 @@
|
||||
<string>Emulation</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QWidget" name="widget_region" native="true">
|
||||
<layout class="QHBoxLayout" name="region_layout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="region_label">
|
||||
<property name="text">
|
||||
<string>Region:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="region_combobox">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Auto-select</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">JPN</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">USA</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">EUR</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">AUS</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">CHN</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">KOR</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">TWN</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="emulation_speed_layout" native="true">
|
||||
<layout class="QHBoxLayout" name="emulation_speed_layout_inner">
|
||||
|
||||
@ -240,6 +240,14 @@ ConfigureSystem::ConfigureSystem(Core::System& system_, QWidget* parent)
|
||||
connect(ui->button_regenerate_mac, &QPushButton::clicked, this, &ConfigureSystem::RefreshMAC);
|
||||
connect(ui->button_linked_console, &QPushButton::clicked, this,
|
||||
&ConfigureSystem::UnlinkConsole);
|
||||
connect(ui->combo_country, qOverload<int>(&QComboBox::currentIndexChanged), this,
|
||||
[this](int index) {
|
||||
CheckCountryValid(static_cast<u8>(ui->combo_country->itemData(index).toInt()));
|
||||
});
|
||||
connect(ui->region_combobox, qOverload<int>(&QComboBox::currentIndexChanged), this,
|
||||
[this]([[maybe_unused]] int index) {
|
||||
CheckCountryValid(static_cast<u8>(ui->combo_country->currentData().toInt()));
|
||||
});
|
||||
|
||||
connect(ui->button_secure_info, &QPushButton::clicked, this, [this] {
|
||||
ui->button_secure_info->setEnabled(false);
|
||||
@ -280,6 +288,8 @@ ConfigureSystem::ConfigureSystem(Core::System& system_, QWidget* parent)
|
||||
ui->combo_country->addItem(tr(country_names.at(i)), i);
|
||||
}
|
||||
}
|
||||
ui->label_country_invalid->setVisible(false);
|
||||
ui->label_country_invalid->setStyleSheet(QStringLiteral("QLabel { color: #ff3333; }"));
|
||||
|
||||
SetupPerGameUI();
|
||||
ConfigureTime();
|
||||
@ -290,6 +300,19 @@ ConfigureSystem::~ConfigureSystem() = default;
|
||||
void ConfigureSystem::SetConfiguration() {
|
||||
enabled = !system.IsPoweredOn();
|
||||
|
||||
if (!Settings::IsConfiguringGlobal()) {
|
||||
ConfigurationShared::SetHighlight(ui->region_label,
|
||||
!Settings::values.region_value.UsingGlobal());
|
||||
const bool is_region_global = Settings::values.region_value.UsingGlobal();
|
||||
ui->region_combobox->setCurrentIndex(
|
||||
is_region_global ? ConfigurationShared::USE_GLOBAL_INDEX
|
||||
: static_cast<int>(Settings::values.region_value.GetValue()) +
|
||||
ConfigurationShared::USE_GLOBAL_OFFSET + 1);
|
||||
} else {
|
||||
// The first item is "auto-select" with actual value -1, so plus one here will do the trick
|
||||
ui->region_combobox->setCurrentIndex(Settings::values.region_value.GetValue() + 1);
|
||||
}
|
||||
|
||||
ui->combo_init_clock->setCurrentIndex(static_cast<u8>(Settings::values.init_clock.GetValue()));
|
||||
QDateTime date_time;
|
||||
date_time.setSecsSinceEpoch(Settings::values.init_time.GetValue());
|
||||
@ -351,6 +374,7 @@ void ConfigureSystem::ReadSystemSettings() {
|
||||
// set the country code
|
||||
country_code = cfg->GetCountryCode();
|
||||
ui->combo_country->setCurrentIndex(ui->combo_country->findData(country_code));
|
||||
CheckCountryValid(country_code);
|
||||
|
||||
// set whether system setup is needed
|
||||
system_setup = cfg->IsSystemSetupNeeded();
|
||||
@ -373,6 +397,10 @@ void ConfigureSystem::ReadSystemSettings() {
|
||||
|
||||
void ConfigureSystem::ApplyConfiguration() {
|
||||
if (enabled) {
|
||||
ConfigurationShared::ApplyPerGameSetting(&Settings::values.region_value,
|
||||
ui->region_combobox,
|
||||
[](s32 index) { return index - 1; });
|
||||
|
||||
bool modified = false;
|
||||
|
||||
// apply username
|
||||
@ -582,6 +610,32 @@ void ConfigureSystem::UnlinkConsole() {
|
||||
RefreshSecureDataStatus();
|
||||
}
|
||||
|
||||
void ConfigureSystem::CheckCountryValid(u8 country) {
|
||||
// TODO(PabloMK7): Make this per-game compatible
|
||||
if (!Settings::IsConfiguringGlobal())
|
||||
return;
|
||||
|
||||
s32 region = ui->region_combobox->currentIndex() - 1;
|
||||
QString label_text;
|
||||
|
||||
if (region != Settings::REGION_VALUE_AUTO_SELECT &&
|
||||
!cfg->IsValidRegionCountry(static_cast<u32>(region), country)) {
|
||||
label_text = tr("Invalid country for configured region");
|
||||
}
|
||||
if (HW::UniqueData::GetSecureInfoA().IsValid()) {
|
||||
region = static_cast<u32>(cfg->GetRegionValue(true));
|
||||
if (!cfg->IsValidRegionCountry(static_cast<u32>(region), country)) {
|
||||
if (!label_text.isEmpty()) {
|
||||
label_text += QString::fromStdString("\n");
|
||||
}
|
||||
label_text += tr("Invalid country for console unique data");
|
||||
}
|
||||
}
|
||||
|
||||
ui->label_country_invalid->setText(label_text);
|
||||
ui->label_country_invalid->setVisible(!label_text.isEmpty());
|
||||
}
|
||||
|
||||
void ConfigureSystem::InstallSecureData(const std::string& from_path, const std::string& to_path) {
|
||||
std::string from =
|
||||
FileUtil::SanitizePath(from_path, FileUtil::DirectorySeparator::PlatformDefault);
|
||||
@ -644,6 +698,7 @@ void ConfigureSystem::SetupPerGameUI() {
|
||||
ui->toggle_lle_applets->setEnabled(Settings::values.lle_applets.UsingGlobal());
|
||||
ui->enable_required_online_lle_modules->setEnabled(
|
||||
Settings::values.enable_required_online_lle_modules.UsingGlobal());
|
||||
ui->region_combobox->setEnabled(Settings::values.region_value.UsingGlobal());
|
||||
return;
|
||||
}
|
||||
|
||||
@ -694,4 +749,7 @@ void ConfigureSystem::SetupPerGameUI() {
|
||||
ConfigurationShared::SetColoredTristate(ui->enable_required_online_lle_modules,
|
||||
Settings::values.enable_required_online_lle_modules,
|
||||
required_online_lle_modules);
|
||||
ConfigurationShared::SetColoredComboBox(
|
||||
ui->region_combobox, ui->region_label,
|
||||
static_cast<u32>(Settings::values.region_value.GetValue(true) + 1));
|
||||
}
|
||||
|
||||
@ -53,6 +53,7 @@ private:
|
||||
void RefreshConsoleID();
|
||||
void RefreshMAC();
|
||||
void UnlinkConsole();
|
||||
void CheckCountryValid(u8 country);
|
||||
|
||||
void InstallSecureData(const std::string& from_path, const std::string& to_path);
|
||||
void RefreshSecureDataStatus();
|
||||
|
||||
@ -64,21 +64,21 @@
|
||||
<string>System Settings</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="0">
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="toggle_new_3ds">
|
||||
<property name="text">
|
||||
<string>Enable New 3DS mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="toggle_lle_applets">
|
||||
<property name="text">
|
||||
<string>Use LLE applets (if installed)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="enable_required_online_lle_modules">
|
||||
<property name="text">
|
||||
<string>Enable required LLE modules for
|
||||
@ -89,6 +89,57 @@ online features (if installed)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="region_label">
|
||||
<property name="text">
|
||||
<string>Region:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="region_combobox">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Auto-select</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">JPN</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">USA</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">EUR</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">AUS</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">CHN</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">KOR</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">TWN</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QLineEdit" name="edit_username">
|
||||
<property name="sizePolicy">
|
||||
@ -297,14 +348,21 @@ online features (if installed)</string>
|
||||
<item row="8" column="1">
|
||||
<widget class="QComboBox" name="combo_country"/>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<item row="9" column="1">
|
||||
<widget class="QLabel" name="label_country_invalid">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="0">
|
||||
<widget class="QLabel" name="label_init_clock">
|
||||
<property name="text">
|
||||
<string>Clock</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<item row="10" column="1">
|
||||
<widget class="QComboBox" name="combo_init_clock">
|
||||
<item>
|
||||
<property name="text">
|
||||
@ -318,28 +376,28 @@ online features (if installed)</string>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="0">
|
||||
<item row="11" column="0">
|
||||
<widget class="QLabel" name="label_init_time">
|
||||
<property name="text">
|
||||
<string>Startup time</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="1">
|
||||
<item row="11" column="1">
|
||||
<widget class="QDateTimeEdit" name="edit_init_time">
|
||||
<property name="displayFormat">
|
||||
<string>yyyy-MM-ddTHH:mm:ss</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="0">
|
||||
<item row="12" column="0">
|
||||
<widget class="QLabel" name="label_init_time_offset">
|
||||
<property name="text">
|
||||
<string>Offset time</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="1">
|
||||
<item row="12" column="1">
|
||||
<layout class="QGridLayout" name="edit_init_time_offset_grid">
|
||||
<item row="0" column="0">
|
||||
<widget class="QSpinBox" name="edit_init_time_offset_days">
|
||||
@ -363,14 +421,14 @@ online features (if installed)</string>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="12" column="0">
|
||||
<item row="13" column="0">
|
||||
<widget class="QLabel" name="label_init_ticks_type">
|
||||
<property name="text">
|
||||
<string>Initial System Ticks</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="1">
|
||||
<item row="13" column="1">
|
||||
<widget class="QComboBox" name="combo_init_ticks_type">
|
||||
<item>
|
||||
<property name="text">
|
||||
@ -384,14 +442,14 @@ online features (if installed)</string>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="13" column="0">
|
||||
<item row="14" column="0">
|
||||
<widget class="QLabel" name="label_init_ticks_value">
|
||||
<property name="text">
|
||||
<string>Initial System Ticks Override</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="13" column="1">
|
||||
<item row="14" column="1">
|
||||
<widget class="QLineEdit" name="edit_init_ticks_value">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
@ -404,21 +462,21 @@ online features (if installed)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="14" column="0">
|
||||
<item row="15" column="0">
|
||||
<widget class="QLabel" name="label_play_coins">
|
||||
<property name="text">
|
||||
<string>Play Coins</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="14" column="1">
|
||||
<item row="15" column="1">
|
||||
<widget class="QSpinBox" name="spinBox_play_coins">
|
||||
<property name="maximum">
|
||||
<number>300</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="15" column="0">
|
||||
<item row="16" column="0">
|
||||
<widget class="QLabel" name="label_steps_per_hour">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Number of steps per hour reported by the pedometer. Range from 0 to 65,535.</p></body></html></string>
|
||||
@ -428,28 +486,28 @@ online features (if installed)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="15" column="1">
|
||||
<item row="16" column="1">
|
||||
<widget class="QSpinBox" name="spinBox_steps_per_hour">
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="16" column="1">
|
||||
<item row="17" column="1">
|
||||
<widget class="QCheckBox" name="toggle_system_setup">
|
||||
<property name="text">
|
||||
<string>Run System Setup when Home Menu is launched</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="17" column="0">
|
||||
<item row="18" column="0">
|
||||
<widget class="QLabel" name="label_console_id">
|
||||
<property name="text">
|
||||
<string>Console ID:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="17" column="1">
|
||||
<item row="18" column="1">
|
||||
<widget class="QPushButton" name="button_regenerate_console_id">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
@ -465,14 +523,14 @@ online features (if installed)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="18" column="0">
|
||||
<item row="19" column="0">
|
||||
<widget class="QLabel" name="label_mac">
|
||||
<property name="text">
|
||||
<string>MAC:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="18" column="1">
|
||||
<item row="19" column="1">
|
||||
<widget class="QPushButton" name="button_regenerate_mac">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
@ -488,21 +546,21 @@ online features (if installed)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="19" column="0">
|
||||
<item row="20" column="0">
|
||||
<widget class="QLabel" name="label_plugin_loader">
|
||||
<property name="text">
|
||||
<string>3GX Plugin Loader:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="19" column="1">
|
||||
<item row="20" column="1">
|
||||
<widget class="QCheckBox" name="plugin_loader">
|
||||
<property name="text">
|
||||
<string>Enable 3GX plugin loader</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="20" column="1">
|
||||
<item row="21" column="1">
|
||||
<widget class="QCheckBox" name="allow_plugin_loader">
|
||||
<property name="text">
|
||||
<string>Allow applications to change plugin loader state</string>
|
||||
|
||||
@ -86,30 +86,227 @@ static constexpr u16 C(const char code[2]) {
|
||||
}
|
||||
|
||||
static const std::array<u16, 187> country_codes = {{
|
||||
0, C("JP"), 0, 0, 0, 0, 0, 0, // 0-7
|
||||
C("AI"), C("AG"), C("AR"), C("AW"), C("BS"), C("BB"), C("BZ"), C("BO"), // 8-15
|
||||
C("BR"), C("VG"), C("CA"), C("KY"), C("CL"), C("CO"), C("CR"), C("DM"), // 16-23
|
||||
C("DO"), C("EC"), C("SV"), C("GF"), C("GD"), C("GP"), C("GT"), C("GY"), // 24-31
|
||||
C("HT"), C("HN"), C("JM"), C("MQ"), C("MX"), C("MS"), C("AN"), C("NI"), // 32-39
|
||||
C("PA"), C("PY"), C("PE"), C("KN"), C("LC"), C("VC"), C("SR"), C("TT"), // 40-47
|
||||
C("TC"), C("US"), C("UY"), C("VI"), C("VE"), 0, 0, 0, // 48-55
|
||||
0, 0, 0, 0, 0, 0, 0, 0, // 56-63
|
||||
C("AL"), C("AU"), C("AT"), C("BE"), C("BA"), C("BW"), C("BG"), C("HR"), // 64-71
|
||||
C("CY"), C("CZ"), C("DK"), C("EE"), C("FI"), C("FR"), C("DE"), C("GR"), // 72-79
|
||||
C("HU"), C("IS"), C("IE"), C("IT"), C("LV"), C("LS"), C("LI"), C("LT"), // 80-87
|
||||
C("LU"), C("MK"), C("MT"), C("ME"), C("MZ"), C("NA"), C("NL"), C("NZ"), // 88-95
|
||||
C("NO"), C("PL"), C("PT"), C("RO"), C("RU"), C("RS"), C("SK"), C("SI"), // 96-103
|
||||
C("ZA"), C("ES"), C("SZ"), C("SE"), C("CH"), C("TR"), C("GB"), C("ZM"), // 104-111
|
||||
C("ZW"), C("AZ"), C("MR"), C("ML"), C("NE"), C("TD"), C("SD"), C("ER"), // 112-119
|
||||
C("DJ"), C("SO"), C("AD"), C("GI"), C("GG"), C("IM"), C("JE"), C("MC"), // 120-127
|
||||
C("TW"), 0, 0, 0, 0, 0, 0, 0, // 128-135
|
||||
C("KR"), 0, 0, 0, 0, 0, 0, 0, // 136-143
|
||||
C("HK"), C("MO"), 0, 0, 0, 0, 0, 0, // 144-151
|
||||
C("ID"), C("SG"), C("TH"), C("PH"), C("MY"), 0, 0, 0, // 152-159
|
||||
C("CN"), 0, 0, 0, 0, 0, 0, 0, // 160-167
|
||||
C("AE"), C("IN"), C("EG"), C("OM"), C("QA"), C("KW"), C("SA"), C("SY"), // 168-175
|
||||
C("BH"), C("JO"), 0, 0, 0, 0, 0, 0, // 176-183
|
||||
C("SM"), C("VA"), C("BM"), // 184-186
|
||||
// 0-7 Japan
|
||||
0,
|
||||
C("JP"),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
|
||||
// 8-15 America
|
||||
C("AI"),
|
||||
C("AG"),
|
||||
C("AR"),
|
||||
C("AW"),
|
||||
C("BS"),
|
||||
C("BB"),
|
||||
C("BZ"),
|
||||
C("BO"),
|
||||
// 16-23 America
|
||||
C("BR"),
|
||||
C("VG"),
|
||||
C("CA"),
|
||||
C("KY"),
|
||||
C("CL"),
|
||||
C("CO"),
|
||||
C("CR"),
|
||||
C("DM"),
|
||||
// 24-31 America
|
||||
C("DO"),
|
||||
C("EC"),
|
||||
C("SV"),
|
||||
C("GF"),
|
||||
C("GD"),
|
||||
C("GP"),
|
||||
C("GT"),
|
||||
C("GY"),
|
||||
// 32-39 America
|
||||
C("HT"),
|
||||
C("HN"),
|
||||
C("JM"),
|
||||
C("MQ"),
|
||||
C("MX"),
|
||||
C("MS"),
|
||||
C("AN"),
|
||||
C("NI"),
|
||||
// 40-47 America
|
||||
C("PA"),
|
||||
C("PY"),
|
||||
C("PE"),
|
||||
C("KN"),
|
||||
C("LC"),
|
||||
C("VC"),
|
||||
C("SR"),
|
||||
C("TT"),
|
||||
// 48-55 America
|
||||
C("TC"),
|
||||
C("US"),
|
||||
C("UY"),
|
||||
C("VI"),
|
||||
C("VE"),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
|
||||
// 56-63 Invalid
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
|
||||
// 64-71 Europe
|
||||
C("AL"),
|
||||
C("AU"),
|
||||
C("AT"),
|
||||
C("BE"),
|
||||
C("BA"),
|
||||
C("BW"),
|
||||
C("BG"),
|
||||
C("HR"),
|
||||
// 72-79 Europe
|
||||
C("CY"),
|
||||
C("CZ"),
|
||||
C("DK"),
|
||||
C("EE"),
|
||||
C("FI"),
|
||||
C("FR"),
|
||||
C("DE"),
|
||||
C("GR"),
|
||||
// 80-87 Europe
|
||||
C("HU"),
|
||||
C("IS"),
|
||||
C("IE"),
|
||||
C("IT"),
|
||||
C("LV"),
|
||||
C("LS"),
|
||||
C("LI"),
|
||||
C("LT"),
|
||||
// 88-95 Europe
|
||||
C("LU"),
|
||||
C("MK"),
|
||||
C("MT"),
|
||||
C("ME"),
|
||||
C("MZ"),
|
||||
C("NA"),
|
||||
C("NL"),
|
||||
C("NZ"),
|
||||
// 96-103 Europe
|
||||
C("NO"),
|
||||
C("PL"),
|
||||
C("PT"),
|
||||
C("RO"),
|
||||
C("RU"),
|
||||
C("RS"),
|
||||
C("SK"),
|
||||
C("SI"),
|
||||
// 104-111 Europe
|
||||
C("ZA"),
|
||||
C("ES"),
|
||||
C("SZ"),
|
||||
C("SE"),
|
||||
C("CH"),
|
||||
C("TR"),
|
||||
C("GB"),
|
||||
C("ZM"),
|
||||
// 112-119 Europe
|
||||
C("ZW"),
|
||||
C("AZ"),
|
||||
C("MR"),
|
||||
C("ML"),
|
||||
C("NE"),
|
||||
C("TD"),
|
||||
C("SD"),
|
||||
C("ER"),
|
||||
// 120-127 Europe
|
||||
C("DJ"),
|
||||
C("SO"),
|
||||
C("AD"),
|
||||
C("GI"),
|
||||
C("GG"),
|
||||
C("IM"),
|
||||
C("JE"),
|
||||
C("MC"),
|
||||
|
||||
// 128-135 Taiwan
|
||||
C("TW"),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
|
||||
// 136-143 Korea
|
||||
C("KR"),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
|
||||
// 144-151 China? (Hong Kong & Macao)
|
||||
C("HK"),
|
||||
C("MO"),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
|
||||
// 152-159 Southeast Asia
|
||||
C("ID"),
|
||||
C("SG"), // USA
|
||||
C("TH"),
|
||||
C("PH"),
|
||||
C("MY"), // USA
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
|
||||
// 160-167 China
|
||||
C("CN"),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
|
||||
// 168-175 Middle East
|
||||
C("AE"), // USA
|
||||
C("IN"), // EUR
|
||||
C("EG"),
|
||||
C("OM"),
|
||||
C("QA"),
|
||||
C("KW"),
|
||||
C("SA"), // USA
|
||||
C("SY"),
|
||||
// 176-183 Middle East
|
||||
C("BH"),
|
||||
C("JO"),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
|
||||
// 184-186 European Microstates
|
||||
C("SM"),
|
||||
C("VA"),
|
||||
C("BM"),
|
||||
}};
|
||||
|
||||
// Based on PKHeX's lists of subregions at
|
||||
@ -218,6 +415,29 @@ u32 Module::GetRegionValue(bool from_secure_info) {
|
||||
return Settings::values.region_value.GetValue();
|
||||
}
|
||||
|
||||
bool Module::IsValidRegionCountry(u32 region, u8 country_code) {
|
||||
switch (region) {
|
||||
case 0: // JPN
|
||||
return country_code == 1;
|
||||
case 1: // USA
|
||||
return (country_code >= 8 && country_code <= 52) || country_code == 153 ||
|
||||
country_code == 156 || country_code == 168 || country_code == 174;
|
||||
case 2: // EUR
|
||||
case 3: // AUS
|
||||
return (country_code >= 64 && country_code <= 127) ||
|
||||
(country_code >= 184 && country_code <= 186) || country_code == 169;
|
||||
case 4: // CHN
|
||||
return country_code == 144 || country_code == 145 || country_code == 160;
|
||||
case 5: // KOR
|
||||
return country_code == 136;
|
||||
case 6: // TWN
|
||||
return country_code == 128;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Module::Interface::GetRegion(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx);
|
||||
|
||||
|
||||
@ -486,6 +486,8 @@ private:
|
||||
public:
|
||||
u32 GetRegionValue(bool from_secure_info);
|
||||
|
||||
static bool IsValidRegionCountry(u32 region, u8 country_code);
|
||||
|
||||
// Utilities for frontend to set config data.
|
||||
// Note: UpdateConfigNANDSavegame should be called after making changes to config data.
|
||||
|
||||
|
||||
@ -408,6 +408,7 @@ ResultStatus Apploader_Artic::Load(std::shared_ptr<Kernel::Process>& process) {
|
||||
return ResultStatus::ErrorArtic;
|
||||
}
|
||||
|
||||
auto cfg = system.ServiceManager().GetService<Service::CFG::CFG_U>("cfg:u");
|
||||
// Request console unique data
|
||||
for (int i = 0; i < 6; i++) {
|
||||
std::string path;
|
||||
@ -471,7 +472,6 @@ ResultStatus Apploader_Artic::Load(std::shared_ptr<Kernel::Process>& process) {
|
||||
memcpy(&console_id, resp_buff->first, sizeof(u64));
|
||||
memcpy(&random_id, reinterpret_cast<u8*>(resp_buff->first) + sizeof(u64),
|
||||
sizeof(u32));
|
||||
auto cfg = system.ServiceManager().GetService<Service::CFG::CFG_U>("cfg:u");
|
||||
if (cfg.get()) {
|
||||
auto cfg_module = cfg->GetModule();
|
||||
cfg_module->SetConsoleUniqueId(random_id, console_id);
|
||||
@ -480,7 +480,6 @@ ResultStatus Apploader_Artic::Load(std::shared_ptr<Kernel::Process>& process) {
|
||||
} else if (i == 5) {
|
||||
std::array<u8, 6> mac;
|
||||
memcpy(mac.data(), resp_buff->first, mac.size());
|
||||
auto cfg = system.ServiceManager().GetService<Service::CFG::CFG_U>("cfg:u");
|
||||
if (cfg.get()) {
|
||||
auto cfg_module = cfg->GetModule();
|
||||
cfg_module->GetMacAddress() = Service::CFG::MacToString(mac);
|
||||
@ -494,10 +493,25 @@ ResultStatus Apploader_Artic::Load(std::shared_ptr<Kernel::Process>& process) {
|
||||
if (!HW::UniqueData::GetCTCert().IsValid() || !HW::UniqueData::GetMovableSed().IsValid() ||
|
||||
!HW::UniqueData::GetSecureInfoA().IsValid() ||
|
||||
!HW::UniqueData::GetLocalFriendCodeSeedB().IsValid()) {
|
||||
LOG_CRITICAL(Loader, "Some console unique data is invalid, aborting...");
|
||||
client->LogOnServer(Network::ArticBaseCommon::LogOnServerType::LOG_ERROR,
|
||||
"Some console unique data is invalid.\n Aborting...");
|
||||
return ResultStatus::ErrorArtic;
|
||||
}
|
||||
|
||||
if (cfg.get()) {
|
||||
auto cfg_module = cfg->GetModule();
|
||||
if (!Service::CFG::Module::IsValidRegionCountry(cfg_module->GetRegionValue(true),
|
||||
cfg_module->GetCountryCode())) {
|
||||
// Report mismatch to server.
|
||||
client->LogOnServer(
|
||||
Network::ArticBaseCommon::LogOnServerType::LOG_ERROR,
|
||||
"The country configuration does not match\n the console region. "
|
||||
"Please select a valid\n country from the emulation settings.");
|
||||
return ResultStatus::ErrorArtic;
|
||||
}
|
||||
cfg_module->SetSystemSetupNeeded(false);
|
||||
}
|
||||
|
||||
// Set deliver arg so that System Settings goes to the update screen directly
|
||||
auto apt = Service::APT::GetModule(system);
|
||||
Service::APT::DeliverArg arg;
|
||||
|
||||
@ -471,6 +471,14 @@ std::optional<Client::Response> Client::Send(Request& request) {
|
||||
return std::optional<Client::Response>(std::move(resp.response));
|
||||
}
|
||||
|
||||
void Client::LogOnServer(ArticBaseCommon::LogOnServerType log_type, const std::string& message) {
|
||||
auto req = NewRequest("__log");
|
||||
req.AddParameterS8(static_cast<s8>(log_type));
|
||||
req.AddParameterBuffer(message.data(), message.size());
|
||||
|
||||
Send(req);
|
||||
}
|
||||
|
||||
void Client::SignalCommunicationError(const std::string& msg) {
|
||||
StopImpl(true);
|
||||
LOG_CRITICAL(Network, "Communication error");
|
||||
|
||||
@ -165,6 +165,8 @@ public:
|
||||
ping_enabled = enable;
|
||||
}
|
||||
|
||||
void LogOnServer(ArticBaseCommon::LogOnServerType log_type, const std::string& message);
|
||||
|
||||
private:
|
||||
static constexpr const int SERVER_VERSION = 2;
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright 2024 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -31,6 +31,12 @@ enum class RequestParameterType : u16 {
|
||||
IN_SMALL_BUFFER = 4,
|
||||
IN_BIG_BUFFER = 5,
|
||||
};
|
||||
enum class LogOnServerType : u8 {
|
||||
LOG_DEBUG = 0,
|
||||
LOG_INFO = 1,
|
||||
LOG_WARNING = 2,
|
||||
LOG_ERROR = 3,
|
||||
};
|
||||
struct RequestParameter {
|
||||
RequestParameterType type{};
|
||||
union {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user