core: Add SMDH region free patch setting (#1541)

This commit is contained in:
PabloMK7 2025-12-29 01:20:26 +01:00 committed by GitHub
parent 41f1be91eb
commit 4085ce6bf8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 81 additions and 34 deletions

View File

@ -51,7 +51,8 @@ enum class BooleanSetting(
USE_ARTIC_BASE_CONTROLLER("use_artic_base_controller", Settings.SECTION_CONTROLS, false),
UPRIGHT_SCREEN("upright_screen", Settings.SECTION_LAYOUT, false),
COMPRESS_INSTALLED_CIA_CONTENT("compress_cia_installs", Settings.SECTION_STORAGE, false),
ANDROID_HIDE_IMAGES("android_hide_images", Settings.SECTION_CORE, false);
ANDROID_HIDE_IMAGES("android_hide_images", Settings.SECTION_CORE, false),
APPLY_REGION_FREE_PATCH("apply_region_free_patch", Settings.SECTION_SYSTEM, true);
override var boolean: Boolean = defaultValue

View File

@ -354,6 +354,15 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
R.array.regionValues,
)
)
add(
SwitchSetting(
BooleanSetting.APPLY_REGION_FREE_PATCH,
R.string.apply_region_free_patch,
R.string.apply_region_free_patch_desc,
BooleanSetting.APPLY_REGION_FREE_PATCH.key,
BooleanSetting.APPLY_REGION_FREE_PATCH.defaultValue
)
)
val systemCountrySetting = object : AbstractShortSetting {
override var short: Short
get() {

View File

@ -262,6 +262,7 @@ void Config::ReadValues() {
ReadSetting("System", Settings::values.plugin_loader_enabled);
ReadSetting("System", Settings::values.allow_plugin_loader);
ReadSetting("System", Settings::values.steps_per_hour);
ReadSetting("System", Settings::values.apply_region_free_patch);
// Camera
using namespace Service::CAM;

View File

@ -413,6 +413,11 @@ steps_per_hour =
plugin_loader =
allow_plugin_loader =
# Apply region free patch to installed applications
# Patches the region of installed applications to be region free, so that they always appear on the home menu.
# 0: Disabled, 1 (default): Enabled
apply_region_free_patch =
[Camera]
# Which camera engine to use for the right outer camera
# blank: a dummy camera that always returns black image

View File

@ -190,6 +190,8 @@
<string name="username">Username</string>
<string name="new_3ds">New 3DS Mode</string>
<string name="lle_applets">Use LLE Applets (if installed)</string>
<string name="apply_region_free_patch">Apply region free patch to installed applications</string>
<string name="apply_region_free_patch_desc">Patches the region of installed applications to be region free, so that they always appear on the home menu.</string>
<string name="enable_required_online_lle_modules">Enable required LLE modules for online features (if installed)</string>
<string name="enable_required_online_lle_modules_desc">Enables the LLE modules required for online multiplayer, eShop access, etc.</string>
<string name="clock">Clock</string>

View File

@ -745,6 +745,7 @@ void QtConfig::ReadSystemValues() {
ReadBasicSetting(Settings::values.steps_per_hour);
ReadBasicSetting(Settings::values.plugin_loader_enabled);
ReadBasicSetting(Settings::values.allow_plugin_loader);
ReadBasicSetting(Settings::values.apply_region_free_patch);
}
qt_config->endGroup();
@ -1276,6 +1277,7 @@ void QtConfig::SaveSystemValues() {
WriteBasicSetting(Settings::values.steps_per_hour);
WriteBasicSetting(Settings::values.plugin_loader_enabled);
WriteBasicSetting(Settings::values.allow_plugin_loader);
WriteBasicSetting(Settings::values.apply_region_free_patch);
}
qt_config->endGroup();

View File

@ -313,6 +313,8 @@ void ConfigureSystem::SetConfiguration() {
ui->region_combobox->setCurrentIndex(Settings::values.region_value.GetValue() + 1);
}
ui->apply_region_free_patch->setChecked(Settings::values.apply_region_free_patch.GetValue());
ui->combo_init_clock->setCurrentIndex(static_cast<u8>(Settings::values.init_clock.GetValue()));
QDateTime date_time;
date_time.setSecsSinceEpoch(Settings::values.init_time.GetValue());
@ -488,6 +490,7 @@ void ConfigureSystem::ApplyConfiguration() {
Settings::values.lle_applets = ui->toggle_lle_applets->isChecked();
Settings::values.enable_required_online_lle_modules =
ui->enable_required_online_lle_modules->isChecked();
Settings::values.apply_region_free_patch.SetValue(ui->apply_region_free_patch->isChecked());
Settings::values.plugin_loader_enabled.SetValue(ui->plugin_loader->isChecked());
Settings::values.allow_plugin_loader.SetValue(ui->allow_plugin_loader->isChecked());
@ -710,6 +713,7 @@ void ConfigureSystem::SetupPerGameUI() {
}
// Hide most settings for now, we can implement them later
ui->apply_region_free_patch->setVisible(false);
ui->label_username->setVisible(false);
ui->label_birthday->setVisible(false);
ui->label_init_clock->setVisible(false);

View File

@ -140,7 +140,18 @@ online features (if installed)</string>
</item>
</widget>
</item>
<item row="4" column="1">
<item row="4" column="0">
<widget class="QCheckBox" name="apply_region_free_patch">
<property name="text">
<string>Apply region free patch to
installed applications.</string>
</property>
<property name="toolTip">
<string>Patches the region of installed applications to be region free, so that they always appear on the home menu.</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLineEdit" name="edit_username">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
@ -153,21 +164,21 @@ online features (if installed)</string>
</property>
</widget>
</item>
<item row="4" column="0">
<item row="5" column="0">
<widget class="QLabel" name="label_username">
<property name="text">
<string>Username</string>
</property>
</widget>
</item>
<item row="5" column="0">
<item row="6" column="0">
<widget class="QLabel" name="label_birthday">
<property name="text">
<string>Birthday</string>
</property>
</widget>
</item>
<item row="5" column="1">
<item row="6" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_birthday2">
<item>
<widget class="QComboBox" name="combo_birthmonth">
@ -238,14 +249,14 @@ online features (if installed)</string>
</item>
</layout>
</item>
<item row="6" column="0">
<item row="7" column="0">
<widget class="QLabel" name="label_language">
<property name="text">
<string>Language</string>
</property>
</widget>
</item>
<item row="6" column="1">
<item row="7" column="1">
<widget class="QComboBox" name="combo_language">
<property name="toolTip">
<string>Note: this can be overridden when region setting is auto-select</string>
@ -312,14 +323,14 @@ online features (if installed)</string>
</item>
</widget>
</item>
<item row="7" column="0">
<item row="8" column="0">
<widget class="QLabel" name="label_sound">
<property name="text">
<string>Sound output mode</string>
</property>
</widget>
</item>
<item row="7" column="1">
<item row="8" column="1">
<widget class="QComboBox" name="combo_sound">
<item>
<property name="text">
@ -338,31 +349,31 @@ online features (if installed)</string>
</item>
</widget>
</item>
<item row="8" column="0">
<item row="9" column="0">
<widget class="QLabel" name="label_country">
<property name="text">
<string>Country</string>
</property>
</widget>
</item>
<item row="8" column="1">
<item row="9" column="1">
<widget class="QComboBox" name="combo_country"/>
</item>
<item row="9" column="1">
<item row="10" column="1">
<widget class="QLabel" name="label_country_invalid">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="10" column="0">
<item row="11" column="0">
<widget class="QLabel" name="label_init_clock">
<property name="text">
<string>Clock</string>
</property>
</widget>
</item>
<item row="10" column="1">
<item row="11" column="1">
<widget class="QComboBox" name="combo_init_clock">
<item>
<property name="text">
@ -376,28 +387,28 @@ online features (if installed)</string>
</item>
</widget>
</item>
<item row="11" column="0">
<item row="12" column="0">
<widget class="QLabel" name="label_init_time">
<property name="text">
<string>Startup time</string>
</property>
</widget>
</item>
<item row="11" column="1">
<item row="12" column="1">
<widget class="QDateTimeEdit" name="edit_init_time">
<property name="displayFormat">
<string>yyyy-MM-ddTHH:mm:ss</string>
</property>
</widget>
</item>
<item row="12" column="0">
<item row="13" column="0">
<widget class="QLabel" name="label_init_time_offset">
<property name="text">
<string>Offset time</string>
</property>
</widget>
</item>
<item row="12" column="1">
<item row="13" 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">
@ -421,14 +432,14 @@ online features (if installed)</string>
</item>
</layout>
</item>
<item row="13" column="0">
<item row="14" column="0">
<widget class="QLabel" name="label_init_ticks_type">
<property name="text">
<string>Initial System Ticks</string>
</property>
</widget>
</item>
<item row="13" column="1">
<item row="14" column="1">
<widget class="QComboBox" name="combo_init_ticks_type">
<item>
<property name="text">
@ -442,14 +453,14 @@ online features (if installed)</string>
</item>
</widget>
</item>
<item row="14" column="0">
<item row="15" column="0">
<widget class="QLabel" name="label_init_ticks_value">
<property name="text">
<string>Initial System Ticks Override</string>
</property>
</widget>
</item>
<item row="14" column="1">
<item row="15" column="1">
<widget class="QLineEdit" name="edit_init_ticks_value">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
@ -462,21 +473,21 @@ online features (if installed)</string>
</property>
</widget>
</item>
<item row="15" column="0">
<item row="16" column="0">
<widget class="QLabel" name="label_play_coins">
<property name="text">
<string>Play Coins</string>
</property>
</widget>
</item>
<item row="15" column="1">
<item row="16" column="1">
<widget class="QSpinBox" name="spinBox_play_coins">
<property name="maximum">
<number>300</number>
</property>
</widget>
</item>
<item row="16" column="0">
<item row="17" column="0">
<widget class="QLabel" name="label_steps_per_hour">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Number of steps per hour reported by the pedometer. Range from 0 to 65,535.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
@ -486,28 +497,28 @@ online features (if installed)</string>
</property>
</widget>
</item>
<item row="16" column="1">
<item row="17" column="1">
<widget class="QSpinBox" name="spinBox_steps_per_hour">
<property name="maximum">
<number>9999</number>
</property>
</widget>
</item>
<item row="17" column="1">
<item row="18" 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="18" column="0">
<item row="19" column="0">
<widget class="QLabel" name="label_console_id">
<property name="text">
<string>Console ID:</string>
</property>
</widget>
</item>
<item row="18" column="1">
<item row="19" column="1">
<widget class="QPushButton" name="button_regenerate_console_id">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
@ -523,14 +534,14 @@ online features (if installed)</string>
</property>
</widget>
</item>
<item row="19" column="0">
<item row="20" column="0">
<widget class="QLabel" name="label_mac">
<property name="text">
<string>MAC:</string>
</property>
</widget>
</item>
<item row="19" column="1">
<item row="20" column="1">
<widget class="QPushButton" name="button_regenerate_mac">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
@ -546,21 +557,21 @@ online features (if installed)</string>
</property>
</widget>
</item>
<item row="20" column="0">
<item row="21" column="0">
<widget class="QLabel" name="label_plugin_loader">
<property name="text">
<string>3GX Plugin Loader</string>
</property>
</widget>
</item>
<item row="20" column="1">
<item row="21" column="1">
<widget class="QCheckBox" name="plugin_loader">
<property name="text">
<string>Enable 3GX plugin loader</string>
</property>
</widget>
</item>
<item row="21" column="1">
<item row="22" column="1">
<widget class="QCheckBox" name="allow_plugin_loader">
<property name="text">
<string>Allow applications to change plugin loader state</string>

View File

@ -253,6 +253,7 @@ void SdlConfig::ReadValues() {
ReadSetting("System", Settings::values.plugin_loader_enabled);
ReadSetting("System", Settings::values.allow_plugin_loader);
ReadSetting("System", Settings::values.steps_per_hour);
ReadSetting("System", Settings::values.apply_region_free_patch);
{
constexpr const char* default_init_time_offset = "0 00:00:00";

View File

@ -153,6 +153,7 @@ void LogSettings() {
log_setting("System_RegionValue", values.region_value.GetValue());
log_setting("System_PluginLoader", values.plugin_loader_enabled.GetValue());
log_setting("System_PluginLoaderAllowed", values.allow_plugin_loader.GetValue());
log_setting("System_ApplyRegionFreePatch", values.apply_region_free_patch.GetValue());
log_setting("Debugging_DelayStartForLLEModules", values.delay_start_for_lle_modules.GetValue());
log_setting("Debugging_UseGdbstub", values.use_gdbstub.GetValue());
log_setting("Debugging_GdbstubPort", values.gdbstub_port.GetValue());

View File

@ -481,6 +481,7 @@ struct Values {
Setting<bool> plugin_loader_enabled{false, "plugin_loader"};
Setting<bool> allow_plugin_loader{true, "allow_plugin_loader"};
Setting<u16> steps_per_hour{0, "steps_per_hour"};
Setting<bool> apply_region_free_patch{true, "apply_region_free_patch"};
// Renderer
SwitchableSetting<GraphicsAPI, true> graphics_api{

View File

@ -116,6 +116,15 @@ ResultVal<std::unique_ptr<FileBackend>> NCCHArchive::OpenFile(const Path& path,
// Load NCCH .code or icon/banner/logo
result = ncch_container.LoadSectionExeFS(openfile_path.exefs_filepath.data(), buffer);
if (result == Loader::ResultStatus::Success && Settings::values.apply_region_free_patch &&
std::memcmp(openfile_path.exefs_filepath.data(), "icon", 4) == 0 &&
buffer.size() >= sizeof(Loader::SMDH)) {
// Change the SMDH region lockout value to be region free
Loader::SMDH* smdh = reinterpret_cast<Loader::SMDH*>(buffer.data());
constexpr u32 REGION_LOCKOUT_REGION_FREE = 0x7FFFFFFF;
smdh->region_lockout = REGION_LOCKOUT_REGION_FREE;
}
std::unique_ptr<DelayGenerator> delay_generator = std::make_unique<ExeFSDelayGenerator>();
file = std::make_unique<NCCHFile>(std::move(buffer), std::move(delay_generator));
} else {