mirror of
https://github.com/Lime3DS/Lime3DS.git
synced 2025-03-13 09:12:27 +01:00
Add enable required LLE modules for online features option
This commit is contained in:
parent
42d77cd720
commit
5083c90aad
@ -567,7 +567,11 @@ object NativeLibrary {
|
||||
@JvmStatic
|
||||
fun createDir(directory: String, directoryName: String): Boolean =
|
||||
if (FileUtil.isNativePath(directory)) {
|
||||
try {
|
||||
CitraApplication.documentsTree.createDir(directory, directoryName)
|
||||
} catch (e: Exception) {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
FileUtil.createDir(directory, directoryName) != null
|
||||
}
|
||||
@ -641,7 +645,11 @@ object NativeLibrary {
|
||||
@JvmStatic
|
||||
fun renameFile(path: String, destinationFilename: String): Boolean =
|
||||
if (FileUtil.isNativePath(path)) {
|
||||
try {
|
||||
CitraApplication.documentsTree.renameFile(path, destinationFilename)
|
||||
} catch (e: Exception) {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
FileUtil.renameFile(path, destinationFilename)
|
||||
}
|
||||
|
@ -17,7 +17,8 @@ enum class BooleanSetting(
|
||||
INSTANT_DEBUG_LOG("instant_debug_log", Settings.SECTION_DEBUG, false),
|
||||
CUSTOM_LAYOUT("custom_layout",Settings.SECTION_LAYOUT,false),
|
||||
DELAY_START_LLE_MODULES("delay_start_for_lle_modules", Settings.SECTION_DEBUG, true),
|
||||
DETERMINISTIC_ASYNC_OPERATIONS("deterministic_async_operations", Settings.SECTION_DEBUG, false);
|
||||
DETERMINISTIC_ASYNC_OPERATIONS("deterministic_async_operations", Settings.SECTION_DEBUG, false),
|
||||
REQUIRED_ONLINE_LLE_MODULES("enable_required_online_lle_modules", Settings.SECTION_SYSTEM, false);
|
||||
|
||||
override var boolean: Boolean = defaultValue
|
||||
|
||||
@ -41,6 +42,7 @@ enum class BooleanSetting(
|
||||
ASYNC_SHADERS,
|
||||
DELAY_START_LLE_MODULES,
|
||||
DETERMINISTIC_ASYNC_OPERATIONS,
|
||||
REQUIRED_ONLINE_LLE_MODULES,
|
||||
)
|
||||
|
||||
fun from(key: String): BooleanSetting? =
|
||||
|
@ -1303,6 +1303,15 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
|
||||
IntSetting.LLE_APPLETS.defaultValue
|
||||
)
|
||||
)
|
||||
add(
|
||||
SwitchSetting(
|
||||
BooleanSetting.REQUIRED_ONLINE_LLE_MODULES,
|
||||
R.string.enable_required_online_lle_modules,
|
||||
R.string.enable_required_online_lle_modules_desc,
|
||||
BooleanSetting.REQUIRED_ONLINE_LLE_MODULES.key,
|
||||
BooleanSetting.REQUIRED_ONLINE_LLE_MODULES.defaultValue
|
||||
)
|
||||
)
|
||||
add(
|
||||
SliderSetting(
|
||||
IntSetting.CPU_CLOCK_SPEED,
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright Citra Emulator Project / Lime3DS Emulator Project
|
||||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -161,8 +161,8 @@ class DocumentsTree {
|
||||
val node = resolvePath(filepath) ?: return false
|
||||
try {
|
||||
val filename = URLDecoder.decode(destinationFilename, FileUtil.DECODE_METHOD)
|
||||
DocumentsContract.renameDocument(context.contentResolver, node.uri!!, filename)
|
||||
node.rename(filename)
|
||||
val newUri = DocumentsContract.renameDocument(context.contentResolver, node.uri!!, filename)
|
||||
node.rename(filename, newUri)
|
||||
return true
|
||||
} catch (e: Exception) {
|
||||
error("[DocumentsTree]: Cannot rename file, error: " + e.message)
|
||||
@ -255,10 +255,11 @@ class DocumentsTree {
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun rename(name: String) {
|
||||
fun rename(name: String, uri: Uri?) {
|
||||
parent ?: return
|
||||
parent!!.removeChild(this)
|
||||
this.name = name
|
||||
this.uri = uri
|
||||
parent!!.addChild(this)
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -235,6 +235,7 @@ void Config::ReadValues() {
|
||||
// System
|
||||
ReadSetting("System", Settings::values.is_new_3ds);
|
||||
ReadSetting("System", Settings::values.lle_applets);
|
||||
ReadSetting("System", Settings::values.enable_required_online_lle_modules);
|
||||
ReadSetting("System", Settings::values.region_value);
|
||||
ReadSetting("System", Settings::values.init_clock);
|
||||
{
|
||||
|
@ -329,6 +329,10 @@ is_new_3ds =
|
||||
# 0 (default): No, 1: Yes
|
||||
lle_applets =
|
||||
|
||||
# Whether to enable LLE modules for online play
|
||||
# 0 (default): No, 1: Yes
|
||||
enable_required_online_lle_modules =
|
||||
|
||||
# The system region that Citra will use during emulation
|
||||
# -1: Auto-select (default), 0: Japan, 1: USA, 2: Europe, 3: Australia, 4: China, 5: Korea, 6: Taiwan
|
||||
region_value =
|
||||
|
@ -778,5 +778,6 @@
|
||||
<string name="delay_start_lle_modules_description">Delays the start of the app when LLE modules are enabled.</string>
|
||||
<string name="deterministic_async_operations">Deterministic Async Operations</string>
|
||||
<string name="deterministic_async_operations_description">Makes async operations deterministic for debugging. Enabling this may cause freezes.</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 needed for online multiplayer, eShop access, etc.</string>
|
||||
</resources>
|
||||
|
@ -725,6 +725,7 @@ void QtConfig::ReadSystemValues() {
|
||||
|
||||
ReadGlobalSetting(Settings::values.is_new_3ds);
|
||||
ReadGlobalSetting(Settings::values.lle_applets);
|
||||
ReadGlobalSetting(Settings::values.enable_required_online_lle_modules);
|
||||
ReadGlobalSetting(Settings::values.region_value);
|
||||
|
||||
if (global) {
|
||||
@ -1248,6 +1249,7 @@ void QtConfig::SaveSystemValues() {
|
||||
|
||||
WriteGlobalSetting(Settings::values.is_new_3ds);
|
||||
WriteGlobalSetting(Settings::values.lle_applets);
|
||||
WriteGlobalSetting(Settings::values.enable_required_online_lle_modules);
|
||||
WriteGlobalSetting(Settings::values.region_value);
|
||||
|
||||
if (global) {
|
||||
|
@ -319,6 +319,8 @@ void ConfigureSystem::SetConfiguration() {
|
||||
|
||||
ui->toggle_new_3ds->setChecked(Settings::values.is_new_3ds.GetValue());
|
||||
ui->toggle_lle_applets->setChecked(Settings::values.lle_applets.GetValue());
|
||||
ui->enable_required_online_lle_modules->setChecked(
|
||||
Settings::values.enable_required_online_lle_modules.GetValue());
|
||||
ui->plugin_loader->setChecked(Settings::values.plugin_loader_enabled.GetValue());
|
||||
ui->allow_plugin_loader->setChecked(Settings::values.allow_plugin_loader.GetValue());
|
||||
}
|
||||
@ -429,6 +431,9 @@ void ConfigureSystem::ApplyConfiguration() {
|
||||
is_new_3ds);
|
||||
ConfigurationShared::ApplyPerGameSetting(&Settings::values.lle_applets,
|
||||
ui->toggle_lle_applets, lle_applets);
|
||||
ConfigurationShared::ApplyPerGameSetting(
|
||||
&Settings::values.enable_required_online_lle_modules,
|
||||
ui->enable_required_online_lle_modules, required_online_lle_modules);
|
||||
|
||||
Settings::values.init_clock =
|
||||
static_cast<Settings::InitClock>(ui->combo_init_clock->currentIndex());
|
||||
@ -451,6 +456,8 @@ void ConfigureSystem::ApplyConfiguration() {
|
||||
Settings::values.init_time_offset = time_offset_days + time_offset_time;
|
||||
Settings::values.is_new_3ds = ui->toggle_new_3ds->isChecked();
|
||||
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.plugin_loader_enabled.SetValue(ui->plugin_loader->isChecked());
|
||||
Settings::values.allow_plugin_loader.SetValue(ui->allow_plugin_loader->isChecked());
|
||||
@ -605,6 +612,8 @@ void ConfigureSystem::SetupPerGameUI() {
|
||||
if (Settings::IsConfiguringGlobal()) {
|
||||
ui->toggle_new_3ds->setEnabled(Settings::values.is_new_3ds.UsingGlobal());
|
||||
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());
|
||||
return;
|
||||
}
|
||||
|
||||
@ -649,4 +658,7 @@ void ConfigureSystem::SetupPerGameUI() {
|
||||
is_new_3ds);
|
||||
ConfigurationShared::SetColoredTristate(ui->toggle_lle_applets, Settings::values.lle_applets,
|
||||
lle_applets);
|
||||
ConfigurationShared::SetColoredTristate(ui->enable_required_online_lle_modules,
|
||||
Settings::values.enable_required_online_lle_modules,
|
||||
required_online_lle_modules);
|
||||
}
|
||||
|
@ -63,6 +63,7 @@ private:
|
||||
Core::System& system;
|
||||
ConfigurationShared::CheckState is_new_3ds;
|
||||
ConfigurationShared::CheckState lle_applets;
|
||||
ConfigurationShared::CheckState required_online_lle_modules;
|
||||
bool enabled = false;
|
||||
|
||||
std::shared_ptr<Service::CFG::Module> cfg;
|
||||
|
@ -78,7 +78,17 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<item row="3" column="0">
|
||||
<widget class="QCheckBox" name="enable_required_online_lle_modules">
|
||||
<property name="text">
|
||||
<string>Enable required LLE modules for online features (if installed)</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Enables the LLE modules needed for online multiplayer, eShop access, etc.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QLineEdit" name="edit_username">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
@ -91,21 +101,21 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_username">
|
||||
<property name="text">
|
||||
<string>Username</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_birthday">
|
||||
<property name="text">
|
||||
<string>Birthday</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<item row="5" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_birthday2">
|
||||
<item>
|
||||
<widget class="QComboBox" name="combo_birthmonth">
|
||||
@ -176,14 +186,14 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_language">
|
||||
<property name="text">
|
||||
<string>Language</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<item row="6" column="1">
|
||||
<widget class="QComboBox" name="combo_language">
|
||||
<property name="toolTip">
|
||||
<string>Note: this can be overridden when region setting is auto-select</string>
|
||||
@ -250,14 +260,14 @@
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="label_sound">
|
||||
<property name="text">
|
||||
<string>Sound output mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<item row="7" column="1">
|
||||
<widget class="QComboBox" name="combo_sound">
|
||||
<item>
|
||||
<property name="text">
|
||||
@ -276,24 +286,24 @@
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<item row="8" column="0">
|
||||
<widget class="QLabel" name="label_country">
|
||||
<property name="text">
|
||||
<string>Country</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<item row="8" column="1">
|
||||
<widget class="QComboBox" name="combo_country"/>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<item row="9" column="0">
|
||||
<widget class="QLabel" name="label_init_clock">
|
||||
<property name="text">
|
||||
<string>Clock</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<item row="9" column="1">
|
||||
<widget class="QComboBox" name="combo_init_clock">
|
||||
<item>
|
||||
<property name="text">
|
||||
@ -307,28 +317,28 @@
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<item row="10" column="0">
|
||||
<widget class="QLabel" name="label_init_time">
|
||||
<property name="text">
|
||||
<string>Startup time</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<item row="10" column="1">
|
||||
<widget class="QDateTimeEdit" name="edit_init_time">
|
||||
<property name="displayFormat">
|
||||
<string>yyyy-MM-ddTHH:mm:ss</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<item row="11" column="0">
|
||||
<widget class="QLabel" name="label_init_time_offset">
|
||||
<property name="text">
|
||||
<string>Offset time</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<item row="11" 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">
|
||||
@ -352,14 +362,14 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="10" column="0">
|
||||
<item row="12" column="0">
|
||||
<widget class="QLabel" name="label_init_ticks_type">
|
||||
<property name="text">
|
||||
<string>Initial System Ticks</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="1">
|
||||
<item row="12" column="1">
|
||||
<widget class="QComboBox" name="combo_init_ticks_type">
|
||||
<item>
|
||||
<property name="text">
|
||||
@ -373,14 +383,14 @@
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="0">
|
||||
<item row="13" column="0">
|
||||
<widget class="QLabel" name="label_init_ticks_value">
|
||||
<property name="text">
|
||||
<string>Initial System Ticks Override</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="1">
|
||||
<item row="13" column="1">
|
||||
<widget class="QLineEdit" name="edit_init_ticks_value">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
@ -393,21 +403,21 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="0">
|
||||
<item row="14" column="0">
|
||||
<widget class="QLabel" name="label_play_coins">
|
||||
<property name="text">
|
||||
<string>Play Coins</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="1">
|
||||
<item row="14" column="1">
|
||||
<widget class="QSpinBox" name="spinBox_play_coins">
|
||||
<property name="maximum">
|
||||
<number>300</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="13" column="0">
|
||||
<item row="15" 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>
|
||||
@ -417,28 +427,28 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="13" column="1">
|
||||
<item row="15" column="1">
|
||||
<widget class="QSpinBox" name="spinBox_steps_per_hour">
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="14" column="1">
|
||||
<item row="16" 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="15" column="0">
|
||||
<item row="17" column="0">
|
||||
<widget class="QLabel" name="label_console_id">
|
||||
<property name="text">
|
||||
<string>Console ID:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="15" column="1">
|
||||
<item row="17" column="1">
|
||||
<widget class="QPushButton" name="button_regenerate_console_id">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
@ -454,14 +464,14 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="16" column="0">
|
||||
<item row="18" column="0">
|
||||
<widget class="QLabel" name="label_mac">
|
||||
<property name="text">
|
||||
<string>MAC:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="16" column="1">
|
||||
<item row="18" column="1">
|
||||
<widget class="QPushButton" name="button_regenerate_mac">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
@ -477,21 +487,21 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="17" column="0">
|
||||
<item row="19" column="0">
|
||||
<widget class="QLabel" name="label_plugin_loader">
|
||||
<property name="text">
|
||||
<string>3GX Plugin Loader:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="17" column="1">
|
||||
<item row="19" column="1">
|
||||
<widget class="QCheckBox" name="plugin_loader">
|
||||
<property name="text">
|
||||
<string>Enable 3GX plugin loader</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="18" column="1">
|
||||
<item row="20" column="1">
|
||||
<widget class="QCheckBox" name="allow_plugin_loader">
|
||||
<property name="text">
|
||||
<string>Allow applications to change plugin loader state</string>
|
||||
|
@ -224,6 +224,7 @@ void SdlConfig::ReadValues() {
|
||||
// System
|
||||
ReadSetting("System", Settings::values.is_new_3ds);
|
||||
ReadSetting("System", Settings::values.lle_applets);
|
||||
ReadSetting("System", Settings::values.enable_required_online_lle_modules);
|
||||
ReadSetting("System", Settings::values.region_value);
|
||||
ReadSetting("System", Settings::values.init_clock);
|
||||
{
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2024 Azahar Emulator Project
|
||||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -70,5 +70,43 @@ HackManager hack_manager = {
|
||||
},
|
||||
}},
|
||||
|
||||
{HackType::ONLINE_LLE_REQUIRED,
|
||||
HackEntry{
|
||||
.mode = HackAllowMode::FORCE,
|
||||
.affected_title_ids =
|
||||
{
|
||||
// eShop
|
||||
0x0004001000020900, // JAP
|
||||
0x0004001000021900, // USA
|
||||
0x0004001000022900, // EUR
|
||||
0x0004001000027900, // KOR
|
||||
0x0004001000028900, // TWN
|
||||
|
||||
// System Settings
|
||||
0x0004001000020000, // JAP
|
||||
0x0004001000021000, // USA
|
||||
0x0004001000022000, // EUR
|
||||
0x0004001000026000, // CHN
|
||||
0x0004001000027000, // KOR
|
||||
0x0004001000028000, // TWN
|
||||
|
||||
// Nintendo Network ID Settings
|
||||
0x000400100002BF00, // JAP
|
||||
0x000400100002C000, // USA
|
||||
0x000400100002C100, // EUR
|
||||
|
||||
// System Settings
|
||||
0x0004003000008202, // JAP
|
||||
0x0004003000008F02, // USA
|
||||
0x0004003000009802, // EUR
|
||||
0x000400300000A102, // CHN
|
||||
0x000400300000A902, // KOR
|
||||
0x000400300000B102, // TWN
|
||||
|
||||
// Pretendo Network's Nimbus
|
||||
0x000400000D40D200,
|
||||
},
|
||||
}},
|
||||
|
||||
}};
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2024 Azahar Emulator Project
|
||||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -12,6 +12,7 @@ enum class HackType : int {
|
||||
RIGHT_EYE_DISABLE,
|
||||
ACCURATE_MULTIPLICATION,
|
||||
DECRYPTION_AUTHORIZED,
|
||||
ONLINE_LLE_REQUIRED,
|
||||
};
|
||||
|
||||
class UserHackData {};
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2024 Azahar Emulator Project
|
||||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -32,6 +32,28 @@ struct HackManager {
|
||||
return (hack != nullptr) ? hack->mode : default_mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the provided boolean setting depending on the hack type for the title ID
|
||||
* If there is no hack, or the hack is set to allow, the setting value is returned
|
||||
* If the hack disallows, false is returned.
|
||||
* If the hack forces, true is returned.
|
||||
*/
|
||||
bool OverrideBooleanSetting(const HackType& type, u64 title_id, bool setting_value) {
|
||||
const HackEntry* hack = GetHack(type, title_id);
|
||||
if (hack == nullptr)
|
||||
return setting_value;
|
||||
switch (hack->mode) {
|
||||
case HackAllowMode::DISALLOW:
|
||||
return false;
|
||||
case HackAllowMode::FORCE:
|
||||
return true;
|
||||
case HackAllowMode::ALLOW:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return setting_value;
|
||||
}
|
||||
|
||||
std::multimap<HackType, HackEntry> entries;
|
||||
};
|
||||
|
||||
|
@ -450,8 +450,10 @@ struct Values {
|
||||
Setting<bool> use_cpu_jit{true, "use_cpu_jit"};
|
||||
SwitchableSetting<s32, true> cpu_clock_percentage{100, 5, 400, "cpu_clock_percentage"};
|
||||
SwitchableSetting<bool> is_new_3ds{true, "is_new_3ds"};
|
||||
SwitchableSetting<bool> lle_applets{false, "lle_applets"};
|
||||
SwitchableSetting<bool> lle_applets{true, "lle_applets"};
|
||||
SwitchableSetting<bool> deterministic_async_operations{false, "deterministic_async_operations"};
|
||||
SwitchableSetting<bool> enable_required_online_lle_modules{
|
||||
false, "enable_required_online_lle_modules"};
|
||||
|
||||
// Data Storage
|
||||
Setting<bool> use_virtual_sd{true, "use_virtual_sd"};
|
||||
|
@ -508,8 +508,10 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window,
|
||||
service_manager = std::make_unique<Service::SM::ServiceManager>(*this);
|
||||
archive_manager = std::make_unique<Service::FS::ArchiveManager>(*this);
|
||||
|
||||
u64 loading_title_id = 0;
|
||||
app_loader->ReadProgramId(loading_title_id);
|
||||
HW::AES::InitKeys();
|
||||
Service::Init(*this, lle_modules, !app_loader->DoingInitialSetup());
|
||||
Service::Init(*this, loading_title_id, lle_modules, !app_loader->DoingInitialSetup());
|
||||
GDBStub::DeferStart();
|
||||
|
||||
if (!registered_image_interface) {
|
||||
|
@ -861,11 +861,6 @@ Result TicketFile::Commit() {
|
||||
ticket_id = ticket.GetTicketID();
|
||||
const auto ticket_path = GetTicketPath(ticket.GetTitleID(), ticket.GetTicketID());
|
||||
|
||||
// Create ticket folder if it does not exist
|
||||
std::string ticket_folder;
|
||||
Common::SplitPath(ticket_path, &ticket_folder, nullptr, nullptr);
|
||||
FileUtil::CreateFullPath(ticket_folder);
|
||||
|
||||
// Save ticket
|
||||
if (ticket.Save(ticket_path) != Loader::ResultStatus::Success) {
|
||||
LOG_ERROR(Service_AM, "Failed to install ticket provided to TicketFile.");
|
||||
@ -1182,6 +1177,13 @@ std::string GetMediaTitlePath(Service::FS::MediaType media_type) {
|
||||
}
|
||||
|
||||
void Module::ScanForTickets() {
|
||||
scan_tickets_future = std::async([this]() {
|
||||
std::scoped_lock lock(am_lists_mutex);
|
||||
ScanForTicketsImpl();
|
||||
});
|
||||
}
|
||||
|
||||
void Module::ScanForTicketsImpl() {
|
||||
am_ticket_list.clear();
|
||||
|
||||
LOG_DEBUG(Service_AM, "Starting ticket scan");
|
||||
@ -1210,6 +1212,13 @@ void Module::ScanForTickets() {
|
||||
}
|
||||
|
||||
void Module::ScanForTitles(Service::FS::MediaType media_type) {
|
||||
scan_titles_future = std::async([this, media_type]() {
|
||||
std::scoped_lock lock(am_lists_mutex);
|
||||
ScanForTitlesImpl(media_type);
|
||||
});
|
||||
}
|
||||
|
||||
void Module::ScanForTitlesImpl(Service::FS::MediaType media_type) {
|
||||
am_title_list[static_cast<u32>(media_type)].clear();
|
||||
|
||||
LOG_DEBUG(Service_AM, "Starting title scan for media_type={}", static_cast<int>(media_type));
|
||||
@ -1245,9 +1254,12 @@ void Module::ScanForTitles(Service::FS::MediaType media_type) {
|
||||
}
|
||||
|
||||
void Module::ScanForAllTitles() {
|
||||
ScanForTickets();
|
||||
ScanForTitles(Service::FS::MediaType::NAND);
|
||||
ScanForTitles(Service::FS::MediaType::SDMC);
|
||||
scan_all_future = std::async([this]() {
|
||||
std::scoped_lock lock(am_lists_mutex);
|
||||
ScanForTicketsImpl();
|
||||
ScanForTitlesImpl(Service::FS::MediaType::NAND);
|
||||
ScanForTitlesImpl(Service::FS::MediaType::SDMC);
|
||||
});
|
||||
}
|
||||
|
||||
Module::Interface::Interface(std::shared_ptr<Module> am, const char* name, u32 max_session)
|
||||
@ -1307,7 +1319,7 @@ void Module::Interface::GetNumPrograms(Kernel::HLERequestContext& ctx) {
|
||||
},
|
||||
true);
|
||||
} else {
|
||||
|
||||
std::scoped_lock lock(am->am_lists_mutex);
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<u32>(static_cast<u32>(am->am_title_list[media_type].size()));
|
||||
@ -1648,6 +1660,7 @@ void Module::Interface::GetProgramList(Kernel::HLERequestContext& ctx) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::scoped_lock lock(am->am_lists_mutex);
|
||||
u32 media_count = static_cast<u32>(am->am_title_list[media_type].size());
|
||||
u32 copied = std::min(media_count, count);
|
||||
|
||||
@ -1660,8 +1673,8 @@ void Module::Interface::GetProgramList(Kernel::HLERequestContext& ctx) {
|
||||
}
|
||||
|
||||
Result GetTitleInfoFromList(std::span<const u64> title_id_list, Service::FS::MediaType media_type,
|
||||
Kernel::MappedBuffer& title_info_out) {
|
||||
std::size_t write_offset = 0;
|
||||
std::vector<TitleInfo>& title_info_out) {
|
||||
title_info_out.reserve(title_id_list.size());
|
||||
for (u32 i = 0; i < title_id_list.size(); i++) {
|
||||
std::string tmd_path = GetTitleMetadataPath(media_type, title_id_list[i]);
|
||||
|
||||
@ -1682,8 +1695,7 @@ Result GetTitleInfoFromList(std::span<const u64> title_id_list, Service::FS::Med
|
||||
}
|
||||
LOG_DEBUG(Service_AM, "found title_id={:016X} version={:04X}", title_id_list[i],
|
||||
title_info.version);
|
||||
title_info_out.Write(&title_info, write_offset, sizeof(TitleInfo));
|
||||
write_offset += sizeof(TitleInfo);
|
||||
title_info_out.push_back(title_info);
|
||||
}
|
||||
|
||||
return ResultSuccess;
|
||||
@ -1773,41 +1785,64 @@ void Module::Interface::GetProgramInfosImpl(Kernel::HLERequestContext& ctx, bool
|
||||
true);
|
||||
|
||||
} else {
|
||||
auto& title_id_list_buffer = rp.PopMappedBuffer();
|
||||
auto& title_info_out = rp.PopMappedBuffer();
|
||||
struct AsyncData {
|
||||
Service::FS::MediaType media_type;
|
||||
std::vector<u64> title_id_list;
|
||||
|
||||
std::vector<u64> title_id_list(title_count);
|
||||
title_id_list_buffer.Read(title_id_list.data(), 0, title_count * sizeof(u64));
|
||||
Result res{0};
|
||||
std::vector<TitleInfo> out;
|
||||
Kernel::MappedBuffer* title_id_list_buffer;
|
||||
Kernel::MappedBuffer* title_info_out;
|
||||
};
|
||||
auto async_data = std::make_shared<AsyncData>();
|
||||
async_data->media_type = media_type;
|
||||
async_data->title_id_list.resize(title_count);
|
||||
async_data->title_id_list_buffer = &rp.PopMappedBuffer();
|
||||
async_data->title_id_list_buffer->Read(async_data->title_id_list.data(), 0,
|
||||
title_count * sizeof(u64));
|
||||
async_data->title_info_out = &rp.PopMappedBuffer();
|
||||
|
||||
ctx.RunAsync(
|
||||
[this, async_data](Kernel::HLERequestContext& ctx) {
|
||||
// nim checks if the current importing title already exists during installation.
|
||||
// Normally, since the program wouldn't be commited, getting the title info returns not
|
||||
// found. However, since GetTitleInfoFromList does not care if the program was commited and
|
||||
// only checks for the tmd, it will detect the title and return information while it
|
||||
// shouldn't. To prevent this, we check if the importing context is present and not
|
||||
// committed. If that's the case, return not found
|
||||
Result result = ResultSuccess;
|
||||
for (auto tid : title_id_list) {
|
||||
// Normally, since the program wouldn't be commited, getting the title info returns
|
||||
// not found. However, since GetTitleInfoFromList does not care if the program was
|
||||
// commited and only checks for the tmd, it will detect the title and return
|
||||
// information while it shouldn't. To prevent this, we check if the importing
|
||||
// context is present and not committed. If that's the case, return not found
|
||||
for (auto tid : async_data->title_id_list) {
|
||||
for (auto& import_ctx : am->import_title_contexts) {
|
||||
if (import_ctx.first == tid &&
|
||||
(import_ctx.second.state == ImportTitleContextState::WAITING_FOR_IMPORT ||
|
||||
import_ctx.second.state == ImportTitleContextState::WAITING_FOR_COMMIT ||
|
||||
(import_ctx.second.state ==
|
||||
ImportTitleContextState::WAITING_FOR_IMPORT ||
|
||||
import_ctx.second.state ==
|
||||
ImportTitleContextState::WAITING_FOR_COMMIT ||
|
||||
import_ctx.second.state == ImportTitleContextState::RESUMABLE)) {
|
||||
LOG_DEBUG(Service_AM, "title pending commit title_id={:016X}", tid);
|
||||
result = Result(ErrorDescription::NotFound, ErrorModule::AM,
|
||||
async_data->res =
|
||||
Result(ErrorDescription::NotFound, ErrorModule::AM,
|
||||
ErrorSummary::InvalidState, ErrorLevel::Permanent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result.IsSuccess())
|
||||
result = GetTitleInfoFromList(title_id_list, media_type, title_info_out);
|
||||
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, ignore_platform ? 0 : 4);
|
||||
rb.Push(result);
|
||||
if (!ignore_platform) {
|
||||
rb.PushMappedBuffer(title_id_list_buffer);
|
||||
rb.PushMappedBuffer(title_info_out);
|
||||
if (async_data->res.IsSuccess()) {
|
||||
async_data->res = GetTitleInfoFromList(async_data->title_id_list,
|
||||
async_data->media_type, async_data->out);
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
[async_data](Kernel::HLERequestContext& ctx) {
|
||||
if (async_data->res.IsSuccess()) {
|
||||
async_data->title_info_out->Write(async_data->out.data(), 0,
|
||||
async_data->out.size() * sizeof(TitleInfo));
|
||||
}
|
||||
IPC::RequestBuilder rb(ctx, 1, 4);
|
||||
rb.Push(async_data->res);
|
||||
rb.PushMappedBuffer(*async_data->title_id_list_buffer);
|
||||
rb.PushMappedBuffer(*async_data->title_info_out);
|
||||
},
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1954,32 +1989,74 @@ void Module::Interface::GetDLCTitleInfos(Kernel::HLERequestContext& ctx) {
|
||||
},
|
||||
true);
|
||||
} else {
|
||||
auto& title_id_list_buffer = rp.PopMappedBuffer();
|
||||
auto& title_info_out = rp.PopMappedBuffer();
|
||||
struct AsyncData {
|
||||
Service::FS::MediaType media_type;
|
||||
std::vector<u64> title_id_list;
|
||||
|
||||
std::vector<u64> title_id_list(title_count);
|
||||
title_id_list_buffer.Read(title_id_list.data(), 0, title_count * sizeof(u64));
|
||||
|
||||
Result result = ResultSuccess;
|
||||
Result res{0};
|
||||
std::vector<TitleInfo> out;
|
||||
Kernel::MappedBuffer* title_id_list_buffer;
|
||||
Kernel::MappedBuffer* title_info_out;
|
||||
};
|
||||
auto async_data = std::make_shared<AsyncData>();
|
||||
async_data->media_type = media_type;
|
||||
async_data->title_id_list.resize(title_count);
|
||||
async_data->title_id_list_buffer = &rp.PopMappedBuffer();
|
||||
async_data->title_id_list_buffer->Read(async_data->title_id_list.data(), 0,
|
||||
title_count * sizeof(u64));
|
||||
async_data->title_info_out = &rp.PopMappedBuffer();
|
||||
|
||||
ctx.RunAsync(
|
||||
[this, async_data](Kernel::HLERequestContext& ctx) {
|
||||
// Validate that DLC TIDs were passed in
|
||||
for (u32 i = 0; i < title_count; i++) {
|
||||
u32 tid_high = static_cast<u32>(title_id_list[i] >> 32);
|
||||
for (u32 i = 0; i < async_data->title_id_list.size(); i++) {
|
||||
u32 tid_high = static_cast<u32>(async_data->title_id_list[i] >> 32);
|
||||
if (tid_high != TID_HIGH_DLC) {
|
||||
result = Result(ErrCodes::InvalidTIDInList, ErrorModule::AM,
|
||||
async_data->res = Result(ErrCodes::InvalidTIDInList, ErrorModule::AM,
|
||||
ErrorSummary::InvalidArgument, ErrorLevel::Usage);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = GetTitleInfoFromList(title_id_list, media_type, title_info_out);
|
||||
// nim checks if the current importing title already exists during installation.
|
||||
// Normally, since the program wouldn't be commited, getting the title info returns
|
||||
// not found. However, since GetTitleInfoFromList does not care if the program was
|
||||
// commited and only checks for the tmd, it will detect the title and return
|
||||
// information while it shouldn't. To prevent this, we check if the importing
|
||||
// context is present and not committed. If that's the case, return not found
|
||||
for (auto tid : async_data->title_id_list) {
|
||||
for (auto& import_ctx : am->import_title_contexts) {
|
||||
if (import_ctx.first == tid &&
|
||||
(import_ctx.second.state ==
|
||||
ImportTitleContextState::WAITING_FOR_IMPORT ||
|
||||
import_ctx.second.state ==
|
||||
ImportTitleContextState::WAITING_FOR_COMMIT ||
|
||||
import_ctx.second.state == ImportTitleContextState::RESUMABLE)) {
|
||||
LOG_DEBUG(Service_AM, "title pending commit title_id={:016X}", tid);
|
||||
async_data->res =
|
||||
Result(ErrorDescription::NotFound, ErrorModule::AM,
|
||||
ErrorSummary::InvalidState, ErrorLevel::Permanent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 4);
|
||||
rb.Push(result);
|
||||
rb.PushMappedBuffer(title_id_list_buffer);
|
||||
rb.PushMappedBuffer(title_info_out);
|
||||
if (async_data->res.IsSuccess()) {
|
||||
async_data->res = GetTitleInfoFromList(async_data->title_id_list,
|
||||
async_data->media_type, async_data->out);
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
[async_data](Kernel::HLERequestContext& ctx) {
|
||||
if (async_data->res.IsSuccess()) {
|
||||
async_data->title_info_out->Write(async_data->out.data(), 0,
|
||||
async_data->out.size() * sizeof(TitleInfo));
|
||||
}
|
||||
IPC::RequestBuilder rb(ctx, 1, 4);
|
||||
rb.Push(async_data->res);
|
||||
rb.PushMappedBuffer(*async_data->title_id_list_buffer);
|
||||
rb.PushMappedBuffer(*async_data->title_info_out);
|
||||
},
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2059,32 +2136,74 @@ void Module::Interface::GetPatchTitleInfos(Kernel::HLERequestContext& ctx) {
|
||||
},
|
||||
true);
|
||||
} else {
|
||||
auto& title_id_list_buffer = rp.PopMappedBuffer();
|
||||
auto& title_info_out = rp.PopMappedBuffer();
|
||||
struct AsyncData {
|
||||
Service::FS::MediaType media_type;
|
||||
std::vector<u64> title_id_list;
|
||||
|
||||
std::vector<u64> title_id_list(title_count);
|
||||
title_id_list_buffer.Read(title_id_list.data(), 0, title_count * sizeof(u64));
|
||||
|
||||
Result result = ResultSuccess;
|
||||
Result res{0};
|
||||
std::vector<TitleInfo> out;
|
||||
Kernel::MappedBuffer* title_id_list_buffer;
|
||||
Kernel::MappedBuffer* title_info_out;
|
||||
};
|
||||
auto async_data = std::make_shared<AsyncData>();
|
||||
async_data->media_type = media_type;
|
||||
async_data->title_id_list.resize(title_count);
|
||||
async_data->title_id_list_buffer = &rp.PopMappedBuffer();
|
||||
async_data->title_id_list_buffer->Read(async_data->title_id_list.data(), 0,
|
||||
title_count * sizeof(u64));
|
||||
async_data->title_info_out = &rp.PopMappedBuffer();
|
||||
|
||||
ctx.RunAsync(
|
||||
[this, async_data](Kernel::HLERequestContext& ctx) {
|
||||
// Validate that update TIDs were passed in
|
||||
for (u32 i = 0; i < title_count; i++) {
|
||||
u32 tid_high = static_cast<u32>(title_id_list[i] >> 32);
|
||||
for (u32 i = 0; i < async_data->title_id_list.size(); i++) {
|
||||
u32 tid_high = static_cast<u32>(async_data->title_id_list[i] >> 32);
|
||||
if (tid_high != TID_HIGH_UPDATE) {
|
||||
result = Result(ErrCodes::InvalidTIDInList, ErrorModule::AM,
|
||||
async_data->res = Result(ErrCodes::InvalidTIDInList, ErrorModule::AM,
|
||||
ErrorSummary::InvalidArgument, ErrorLevel::Usage);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = GetTitleInfoFromList(title_id_list, media_type, title_info_out);
|
||||
// nim checks if the current importing title already exists during installation.
|
||||
// Normally, since the program wouldn't be commited, getting the title info returns
|
||||
// not found. However, since GetTitleInfoFromList does not care if the program was
|
||||
// commited and only checks for the tmd, it will detect the title and return
|
||||
// information while it shouldn't. To prevent this, we check if the importing
|
||||
// context is present and not committed. If that's the case, return not found
|
||||
for (auto tid : async_data->title_id_list) {
|
||||
for (auto& import_ctx : am->import_title_contexts) {
|
||||
if (import_ctx.first == tid &&
|
||||
(import_ctx.second.state ==
|
||||
ImportTitleContextState::WAITING_FOR_IMPORT ||
|
||||
import_ctx.second.state ==
|
||||
ImportTitleContextState::WAITING_FOR_COMMIT ||
|
||||
import_ctx.second.state == ImportTitleContextState::RESUMABLE)) {
|
||||
LOG_DEBUG(Service_AM, "title pending commit title_id={:016X}", tid);
|
||||
async_data->res =
|
||||
Result(ErrorDescription::NotFound, ErrorModule::AM,
|
||||
ErrorSummary::InvalidState, ErrorLevel::Permanent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 4);
|
||||
rb.Push(result);
|
||||
rb.PushMappedBuffer(title_id_list_buffer);
|
||||
rb.PushMappedBuffer(title_info_out);
|
||||
if (async_data->res.IsSuccess()) {
|
||||
async_data->res = GetTitleInfoFromList(async_data->title_id_list,
|
||||
async_data->media_type, async_data->out);
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
[async_data](Kernel::HLERequestContext& ctx) {
|
||||
if (async_data->res.IsSuccess()) {
|
||||
async_data->title_info_out->Write(async_data->out.data(), 0,
|
||||
async_data->out.size() * sizeof(TitleInfo));
|
||||
}
|
||||
IPC::RequestBuilder rb(ctx, 1, 4);
|
||||
rb.Push(async_data->res);
|
||||
rb.PushMappedBuffer(*async_data->title_id_list_buffer);
|
||||
rb.PushMappedBuffer(*async_data->title_info_out);
|
||||
},
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2266,6 +2385,7 @@ void Module::Interface::DeleteTicket(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "title_id={:016X}", title_id);
|
||||
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||
std::scoped_lock lock(am->am_lists_mutex);
|
||||
auto range = am->am_ticket_list.equal_range(title_id);
|
||||
if (range.first == range.second) {
|
||||
rb.Push(Result(ErrorDescription::AlreadyDone, ErrorModule::AM, ErrorSummary::Success,
|
||||
@ -2288,6 +2408,7 @@ void Module::Interface::GetNumTickets(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
LOG_DEBUG(Service_AM, "");
|
||||
|
||||
std::scoped_lock lock(am->am_lists_mutex);
|
||||
u32 ticket_count = static_cast<u32>(am->am_ticket_list.size());
|
||||
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
||||
@ -2304,6 +2425,7 @@ void Module::Interface::GetTicketList(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "ticket_list_count={}, ticket_index={}", ticket_list_count, ticket_index);
|
||||
|
||||
u32 tickets_written = 0;
|
||||
std::scoped_lock lock(am->am_lists_mutex);
|
||||
auto it = am->am_ticket_list.begin();
|
||||
std::advance(it, std::min(static_cast<size_t>(ticket_index), am->am_ticket_list.size()));
|
||||
|
||||
@ -2631,6 +2753,7 @@ void Module::Interface::GetPersonalizedTicketInfoList(Kernel::HLERequestContext&
|
||||
LOG_DEBUG(Service_AM, "(STUBBED) called, ticket_count={}", ticket_count);
|
||||
|
||||
u32 written = 0;
|
||||
std::scoped_lock lock(am->am_lists_mutex);
|
||||
for (auto it = am->am_ticket_list.begin();
|
||||
it != am->am_ticket_list.end() && written < ticket_count; it++) {
|
||||
u64 title_id = it->first;
|
||||
@ -3285,6 +3408,7 @@ void Module::Interface::EndImportTicket(Kernel::HLERequestContext& ctx) {
|
||||
auto ticket_file = GetFileBackendFromSession<TicketFile>(ticket);
|
||||
if (ticket_file.Succeeded()) {
|
||||
rb.Push(ticket_file.Unwrap()->Commit());
|
||||
std::scoped_lock lock(am->am_lists_mutex);
|
||||
am->am_ticket_list.insert(std::make_pair(ticket_file.Unwrap()->GetTitleID(),
|
||||
ticket_file.Unwrap()->GetTicketID()));
|
||||
} else {
|
||||
@ -3308,6 +3432,7 @@ void Module::Interface::BeginImportTitle(Kernel::HLERequestContext& ctx) {
|
||||
am->importing_title =
|
||||
std::make_shared<CurrentImportingTitle>(Core::System::GetInstance(), title_id, media_type);
|
||||
|
||||
std::scoped_lock lock(am->am_lists_mutex);
|
||||
auto entries = am->am_ticket_list.find(title_id);
|
||||
if (entries == am->am_ticket_list.end()) {
|
||||
// Ticket is not installed
|
||||
@ -3770,11 +3895,11 @@ void Module::Interface::Sign(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
template <class Archive>
|
||||
void Module::serialize(Archive& ar, const unsigned int) {
|
||||
std::scoped_lock lock(am_lists_mutex);
|
||||
DEBUG_SERIALIZATION_POINT;
|
||||
ar & cia_installing;
|
||||
ar & force_old_device_id;
|
||||
ar & force_new_device_id;
|
||||
ar & am_title_list;
|
||||
ar & system_updater_mutex;
|
||||
}
|
||||
SERIALIZE_IMPL(Module)
|
||||
@ -3815,6 +3940,7 @@ void Module::Interface::DeleteTicketId(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "title_id={:016X} ticket_id={}", title_id, ticket_id);
|
||||
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||
std::scoped_lock lock(am->am_lists_mutex);
|
||||
auto range = am->am_ticket_list.equal_range(title_id);
|
||||
auto it = range.first;
|
||||
for (; it != range.second; it++) {
|
||||
@ -3842,6 +3968,7 @@ void Module::Interface::GetNumTicketIds(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
LOG_DEBUG(Service_AM, "title_id={:016X}", title_id);
|
||||
|
||||
std::scoped_lock lock(am->am_lists_mutex);
|
||||
auto range = am->am_ticket_list.equal_range(title_id);
|
||||
u32 count = static_cast<u32>(std::distance(range.first, range.second));
|
||||
|
||||
@ -3861,6 +3988,7 @@ void Module::Interface::GetTicketIdList(Kernel::HLERequestContext& ctx) {
|
||||
auto out_buf = rp.PopMappedBuffer();
|
||||
|
||||
u32 index = 0;
|
||||
std::scoped_lock lock(am->am_lists_mutex);
|
||||
for (auto [it, rangeEnd] = am->am_ticket_list.equal_range(title_id);
|
||||
it != rangeEnd && index < list_count; index++, it++) {
|
||||
u64 ticket_id = it->second;
|
||||
@ -3878,6 +4006,7 @@ void Module::Interface::GetNumTicketsOfProgram(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
LOG_DEBUG(Service_AM, "title_id={:016X}", title_id);
|
||||
|
||||
std::scoped_lock lock(am->am_lists_mutex);
|
||||
auto range = am->am_ticket_list.equal_range(title_id);
|
||||
u32 count = static_cast<u32>(std::distance(range.first, range.second));
|
||||
|
||||
@ -3895,6 +4024,7 @@ void Module::Interface::ListTicketInfos(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
LOG_DEBUG(Service_AM, "(STUBBED) called, ticket_count={}", ticket_count);
|
||||
|
||||
std::scoped_lock lock(am->am_lists_mutex);
|
||||
auto range = am->am_ticket_list.equal_range(title_id);
|
||||
auto it = range.first;
|
||||
std::advance(it, std::min(static_cast<size_t>(skip),
|
||||
@ -3943,6 +4073,7 @@ void Module::Interface::ExportTicketWrapped(Kernel::HLERequestContext& ctx) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::scoped_lock lock(am->am_lists_mutex);
|
||||
auto range = am->am_ticket_list.equal_range(title_id);
|
||||
auto it = range.first;
|
||||
for (; it != range.second; it++)
|
||||
@ -4006,6 +4137,7 @@ void Module::Interface::ExportTicketWrapped(Kernel::HLERequestContext& ctx) {
|
||||
}
|
||||
|
||||
Module::Module(Core::System& _system) : system(_system) {
|
||||
FileUtil::CreateFullPath(GetTicketDirectory());
|
||||
ScanForAllTitles();
|
||||
system_updater_mutex = system.Kernel().CreateMutex(false, "AM::SystemUpdaterMutex");
|
||||
}
|
||||
|
@ -6,7 +6,9 @@
|
||||
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <future>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <boost/serialization/array.hpp>
|
||||
@ -1022,12 +1024,16 @@ public:
|
||||
private:
|
||||
void ScanForTickets();
|
||||
|
||||
void ScanForTicketsImpl();
|
||||
|
||||
/**
|
||||
* Scans the for titles in a storage medium for listing.
|
||||
* @param media_type the storage medium to scan
|
||||
*/
|
||||
void ScanForTitles(Service::FS::MediaType media_type);
|
||||
|
||||
void ScanForTitlesImpl(Service::FS::MediaType media_type);
|
||||
|
||||
/**
|
||||
* Scans all storage mediums for titles for listing.
|
||||
*/
|
||||
@ -1037,6 +1043,10 @@ private:
|
||||
bool cia_installing = false;
|
||||
bool force_old_device_id = false;
|
||||
bool force_new_device_id = false;
|
||||
std::future<void> scan_tickets_future;
|
||||
std::future<void> scan_titles_future;
|
||||
std::future<void> scan_all_future;
|
||||
std::mutex am_lists_mutex;
|
||||
std::array<std::vector<u64_le>, 3> am_title_list;
|
||||
std::multimap<u64, u64> am_ticket_list;
|
||||
std::shared_ptr<Kernel::Mutex> system_updater_mutex;
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <algorithm>
|
||||
#include <fmt/format.h>
|
||||
#include "common/assert.h"
|
||||
#include "common/hacks/hack_manager.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/ipc.h"
|
||||
@ -59,53 +60,54 @@
|
||||
namespace Service {
|
||||
|
||||
const std::array<ServiceModuleInfo, 41> service_module_map{
|
||||
{{"FS", 0x00040130'00001102, FS::InstallInterfaces},
|
||||
{"PM", 0x00040130'00001202, PM::InstallInterfaces},
|
||||
{"LDR", 0x00040130'00003702, LDR::InstallInterfaces},
|
||||
{"PXI", 0x00040130'00001402, PXI::InstallInterfaces},
|
||||
{{"FS", 0x00040130'00001102, FS::InstallInterfaces, false},
|
||||
{"PM", 0x00040130'00001202, PM::InstallInterfaces, false},
|
||||
{"LDR", 0x00040130'00003702, LDR::InstallInterfaces, false},
|
||||
{"PXI", 0x00040130'00001402, PXI::InstallInterfaces, false},
|
||||
|
||||
{"ERR", 0x00040030'00008A02, ERR::InstallInterfaces},
|
||||
{"AC", 0x00040130'00002402, AC::InstallInterfaces},
|
||||
{"ACT", 0x00040130'00003802, ACT::InstallInterfaces},
|
||||
{"AM", 0x00040130'00001502, AM::InstallInterfaces},
|
||||
{"BOSS", 0x00040130'00003402, BOSS::InstallInterfaces},
|
||||
{"ERR", 0x00040030'00008A02, ERR::InstallInterfaces, false},
|
||||
{"AC", 0x00040130'00002402, AC::InstallInterfaces, false},
|
||||
{"ACT", 0x00040130'00003802, ACT::InstallInterfaces, true},
|
||||
{"AM", 0x00040130'00001502, AM::InstallInterfaces, false},
|
||||
{"BOSS", 0x00040130'00003402, BOSS::InstallInterfaces, false},
|
||||
{"CAM", 0x00040130'00001602,
|
||||
[](Core::System& system) {
|
||||
CAM::InstallInterfaces(system);
|
||||
Y2R::InstallInterfaces(system);
|
||||
}},
|
||||
{"CECD", 0x00040130'00002602, CECD::InstallInterfaces},
|
||||
{"CFG", 0x00040130'00001702, CFG::InstallInterfaces},
|
||||
{"DLP", 0x00040130'00002802, DLP::InstallInterfaces},
|
||||
{"DSP", 0x00040130'00001A02, DSP::InstallInterfaces},
|
||||
{"FRD", 0x00040130'00003202, FRD::InstallInterfaces},
|
||||
{"GSP", 0x00040130'00001C02, GSP::InstallInterfaces},
|
||||
{"HID", 0x00040130'00001D02, HID::InstallInterfaces},
|
||||
{"IR", 0x00040130'00003302, IR::InstallInterfaces},
|
||||
{"MIC", 0x00040130'00002002, MIC::InstallInterfaces},
|
||||
{"MVD", 0x00040130'20004102, MVD::InstallInterfaces},
|
||||
{"NDM", 0x00040130'00002B02, NDM::InstallInterfaces},
|
||||
{"NEWS", 0x00040130'00003502, NEWS::InstallInterfaces},
|
||||
{"NFC", 0x00040130'00004002, NFC::InstallInterfaces},
|
||||
{"NIM", 0x00040130'00002C02, NIM::InstallInterfaces},
|
||||
{"NS", 0x00040130'00008002, APT::InstallInterfaces},
|
||||
{"NWM", 0x00040130'00002D02, NWM::InstallInterfaces},
|
||||
{"PTM", 0x00040130'00002202, PTM::InstallInterfaces},
|
||||
{"QTM", 0x00040130'00004202, QTM::InstallInterfaces},
|
||||
{"CSND", 0x00040130'00002702, CSND::InstallInterfaces},
|
||||
{"HTTP", 0x00040130'00002902, HTTP::InstallInterfaces},
|
||||
{"SOC", 0x00040130'00002E02, SOC::InstallInterfaces},
|
||||
{"SSL", 0x00040130'00002F02, SSL::InstallInterfaces},
|
||||
{"PS", 0x00040130'00003102, PS::InstallInterfaces},
|
||||
{"PLGLDR", 0x00040130'00006902, PLGLDR::InstallInterfaces},
|
||||
},
|
||||
false},
|
||||
{"CECD", 0x00040130'00002602, CECD::InstallInterfaces, false},
|
||||
{"CFG", 0x00040130'00001702, CFG::InstallInterfaces, false},
|
||||
{"DLP", 0x00040130'00002802, DLP::InstallInterfaces, false},
|
||||
{"DSP", 0x00040130'00001A02, DSP::InstallInterfaces, false},
|
||||
{"FRD", 0x00040130'00003202, FRD::InstallInterfaces, true},
|
||||
{"GSP", 0x00040130'00001C02, GSP::InstallInterfaces, false},
|
||||
{"HID", 0x00040130'00001D02, HID::InstallInterfaces, false},
|
||||
{"IR", 0x00040130'00003302, IR::InstallInterfaces, false},
|
||||
{"MIC", 0x00040130'00002002, MIC::InstallInterfaces, false},
|
||||
{"MVD", 0x00040130'20004102, MVD::InstallInterfaces, false},
|
||||
{"NDM", 0x00040130'00002B02, NDM::InstallInterfaces, false},
|
||||
{"NEWS", 0x00040130'00003502, NEWS::InstallInterfaces, false},
|
||||
{"NFC", 0x00040130'00004002, NFC::InstallInterfaces, false},
|
||||
{"NIM", 0x00040130'00002C02, NIM::InstallInterfaces, true},
|
||||
{"NS", 0x00040130'00008002, APT::InstallInterfaces, false},
|
||||
{"NWM", 0x00040130'00002D02, NWM::InstallInterfaces, false},
|
||||
{"PTM", 0x00040130'00002202, PTM::InstallInterfaces, false},
|
||||
{"QTM", 0x00040130'00004202, QTM::InstallInterfaces, false},
|
||||
{"CSND", 0x00040130'00002702, CSND::InstallInterfaces, false},
|
||||
{"HTTP", 0x00040130'00002902, HTTP::InstallInterfaces, false},
|
||||
{"SOC", 0x00040130'00002E02, SOC::InstallInterfaces, false},
|
||||
{"SSL", 0x00040130'00002F02, SSL::InstallInterfaces, false},
|
||||
{"PS", 0x00040130'00003102, PS::InstallInterfaces, false},
|
||||
{"PLGLDR", 0x00040130'00006902, PLGLDR::InstallInterfaces, false},
|
||||
{"MCU", 0x00040130'00001F02, MCU::InstallInterfaces, false},
|
||||
// no HLE implementation
|
||||
{"CDC", 0x00040130'00001802, nullptr},
|
||||
{"GPIO", 0x00040130'00001B02, nullptr},
|
||||
{"I2C", 0x00040130'00001E02, nullptr},
|
||||
{"MCU", 0x00040130'00001F02, MCU::InstallInterfaces},
|
||||
{"MP", 0x00040130'00002A02, nullptr},
|
||||
{"PDN", 0x00040130'00002102, nullptr},
|
||||
{"SPI", 0x00040130'00002302, nullptr}}};
|
||||
{"CDC", 0x00040130'00001802, nullptr, false},
|
||||
{"GPIO", 0x00040130'00001B02, nullptr, false},
|
||||
{"I2C", 0x00040130'00001E02, nullptr, false},
|
||||
{"MP", 0x00040130'00002A02, nullptr, false},
|
||||
{"PDN", 0x00040130'00002102, nullptr, false},
|
||||
{"SPI", 0x00040130'00002302, nullptr, false}}};
|
||||
|
||||
/**
|
||||
* Creates a function string for logging, complete with the name (or header code, depending
|
||||
@ -195,8 +197,13 @@ std::string ServiceFrameworkBase::GetFunctionName(IPC::Header header) const {
|
||||
return itr->second.name;
|
||||
}
|
||||
|
||||
static bool AttemptLLE(const ServiceModuleInfo& service_module) {
|
||||
if (!Settings::values.lle_modules.at(service_module.name))
|
||||
static bool AttemptLLE(const ServiceModuleInfo& service_module, u64 loading_titleid) {
|
||||
const bool enable_recommended_lle_modules = Common::Hacks::hack_manager.OverrideBooleanSetting(
|
||||
Common::Hacks::HackType::ONLINE_LLE_REQUIRED, loading_titleid,
|
||||
Settings::values.enable_required_online_lle_modules.GetValue());
|
||||
|
||||
if (!Settings::values.lle_modules.at(service_module.name) &&
|
||||
(!enable_recommended_lle_modules || !service_module.is_online_recommended))
|
||||
return false;
|
||||
std::unique_ptr<Loader::AppLoader> loader =
|
||||
Loader::GetLoader(AM::GetTitleContentPath(FS::MediaType::NAND, service_module.title_id));
|
||||
@ -220,7 +227,7 @@ static bool AttemptLLE(const ServiceModuleInfo& service_module) {
|
||||
}
|
||||
|
||||
/// Initialize ServiceManager
|
||||
void Init(Core::System& core, std::vector<u64>& lle_modules, bool allow_lle) {
|
||||
void Init(Core::System& core, u64 loading_titleid, std::vector<u64>& lle_modules, bool allow_lle) {
|
||||
SM::ServiceManager::InstallInterfaces(core);
|
||||
core.Kernel().SetAppMainThreadExtendedSleep(false);
|
||||
bool lle_module_present = false;
|
||||
@ -237,7 +244,7 @@ void Init(Core::System& core, std::vector<u64>& lle_modules, bool allow_lle) {
|
||||
|
||||
const bool has_lle = allow_lle &&
|
||||
core.GetSaveStateStatus() != Core::System::SaveStateStatus::LOADING &&
|
||||
AttemptLLE(service_module);
|
||||
AttemptLLE(service_module, loading_titleid);
|
||||
if (has_lle) {
|
||||
lle_modules.push_back(service_module.title_id);
|
||||
}
|
||||
|
@ -184,12 +184,13 @@ private:
|
||||
};
|
||||
|
||||
/// Initialize ServiceManager
|
||||
void Init(Core::System& system, std::vector<u64>& lle_modules, bool allow_lle);
|
||||
void Init(Core::System& system, u64 loading_titleid, std::vector<u64>& lle_modules, bool allow_lle);
|
||||
|
||||
struct ServiceModuleInfo {
|
||||
std::string name;
|
||||
u64 title_id;
|
||||
std::function<void(Core::System&)> init_function;
|
||||
bool is_online_recommended;
|
||||
};
|
||||
|
||||
extern const std::array<ServiceModuleInfo, 41> service_module_map;
|
||||
|
Loading…
x
Reference in New Issue
Block a user