Add LLE modules for online features option + AM Refactor w/ various improvements/fixes

- Added option to enable required LLE modules for online features.
- (Android) Fixed bug that would cause FS RenameFile to fail sometimes on Android.
- (Android) Moved New 3DS mode and LLE applets to system settings tab on Android.
- (Android) Fixed cfg save data related issues (mostly Console ID).
- Made AM title scanning asynchronous, which makes game boot way faster on Android on most cases.
- Made more AM functions asynchronous, to prevent stutter.
- Fixed bug in SOC that could cause the emulator to crash when disconnecting.
- Fixed keys not being initialized when processing console unique files.
This commit is contained in:
PabloMK7
2025-03-13 20:47:21 +00:00
committed by OpenSauce04
parent 518b3d7432
commit d5745cae8f
31 changed files with 646 additions and 254 deletions

View File

@@ -567,7 +567,11 @@ object NativeLibrary {
@JvmStatic
fun createDir(directory: String, directoryName: String): Boolean =
if (FileUtil.isNativePath(directory)) {
CitraApplication.documentsTree.createDir(directory, directoryName)
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)) {
CitraApplication.documentsTree.renameFile(path, destinationFilename)
try {
CitraApplication.documentsTree.renameFile(path, destinationFilename)
} catch (e: Exception) {
false
}
} else {
FileUtil.renameFile(path, destinationFilename)
}

View File

@@ -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? =

View File

@@ -1,4 +1,4 @@
// Copyright 2023 Citra Emulator Project
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -44,7 +44,7 @@ enum class IntSetting(
PORTRAIT_BOTTOM_HEIGHT("custom_portrait_bottom_height",Settings.SECTION_LAYOUT,480),
AUDIO_INPUT_TYPE("output_type", Settings.SECTION_AUDIO, 0),
NEW_3DS("is_new_3ds", Settings.SECTION_SYSTEM, 1),
LLE_APPLETS("lle_applets", Settings.SECTION_SYSTEM, 0),
LLE_APPLETS("lle_applets", Settings.SECTION_SYSTEM, 1),
CPU_CLOCK_SPEED("cpu_clock_percentage", Settings.SECTION_CORE, 100),
LINEAR_FILTERING("filter_mode", Settings.SECTION_RENDERER, 1),
SHADERS_ACCURATE_MUL("shaders_accurate_mul", Settings.SECTION_RENDERER, 0),

View File

@@ -110,6 +110,16 @@ class SettingsActivity : AppCompatActivity(), SettingsActivityView {
presenter.saveState(outState)
}
override fun onPause() {
super.onPause()
presenter.onPause()
}
override fun onResume() {
super.onResume()
presenter.onResume()
}
override fun onStart() {
super.onStart()
presenter.onStart()

View File

@@ -1,4 +1,4 @@
// Copyright 2023 Citra Emulator Project
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -28,8 +28,15 @@ class SettingsActivityPresenter(private val activityView: SettingsActivityView)
}
}
fun onStart() {
fun onResume() {
SystemSaveGame.load()
}
fun onPause() {
SystemSaveGame.save()
}
fun onStart() {
prepareDirectoriesIfNeeded()
}
@@ -56,7 +63,6 @@ class SettingsActivityPresenter(private val activityView: SettingsActivityView)
if (finishing && shouldSave) {
Log.debug("[SettingsActivity] Settings activity stopping. Saving settings to INI...")
settings.saveSettings(activityView)
SystemSaveGame.save()
//added to ensure that layout changes take effect as soon as settings window closes
NativeLibrary.reloadSettings()
NativeLibrary.updateFramebuffer(NativeLibrary.isPortraitMode)

View File

@@ -253,6 +253,35 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
override val valueAsString get() = string
override val defaultValue = "AZAHAR"
}
add(HeaderSetting(R.string.emulation_settings))
add(
SwitchSetting(
IntSetting.NEW_3DS,
R.string.new_3ds,
0,
IntSetting.NEW_3DS.key,
IntSetting.NEW_3DS.defaultValue
)
)
add(
SwitchSetting(
IntSetting.LLE_APPLETS,
R.string.lle_applets,
0,
IntSetting.LLE_APPLETS.key,
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(HeaderSetting(R.string.profile_settings))
add(
StringInputSetting(
usernameSetting,
@@ -1285,24 +1314,6 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.preferences_debug))
sl.apply {
add(HeaderSetting(R.string.debug_warning))
add(
SwitchSetting(
IntSetting.NEW_3DS,
R.string.new_3ds,
0,
IntSetting.NEW_3DS.key,
IntSetting.NEW_3DS.defaultValue
)
)
add(
SwitchSetting(
IntSetting.LLE_APPLETS,
R.string.lle_applets,
0,
IntSetting.LLE_APPLETS.key,
IntSetting.LLE_APPLETS.defaultValue
)
)
add(
SliderSetting(
IntSetting.CPU_CLOCK_SPEED,

View File

@@ -87,6 +87,11 @@ class SystemFilesFragment : Fragment() {
}
}
override fun onResume() {
super.onResume()
SystemSaveGame.load()
}
override fun onPause() {
super.onPause()
SystemSaveGame.save()

View File

@@ -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)
}

View File

@@ -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);
{

View File

@@ -326,9 +326,13 @@ use_virtual_sd =
is_new_3ds =
# Whether to use LLE system applets, if installed
# 0 (default): No, 1: Yes
# 0: No, 1 (default): 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 =

View File

@@ -1,4 +1,4 @@
// Copyright 2023 Citra Emulator Project
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -8,17 +8,22 @@
#include <core/hle/service/ptm/ptm.h>
#include "android_common/android_common.h"
static bool changes_pending = false;
std::shared_ptr<Service::CFG::Module> cfg;
extern "C" {
void Java_org_citra_citra_1emu_utils_SystemSaveGame_save([[maybe_unused]] JNIEnv* env,
[[maybe_unused]] jobject obj) {
cfg->UpdateConfigNANDSavegame();
if (changes_pending) {
changes_pending = false;
cfg->UpdateConfigNANDSavegame();
}
}
void Java_org_citra_citra_1emu_utils_SystemSaveGame_load([[maybe_unused]] JNIEnv* env,
[[maybe_unused]] jobject obj) {
cfg.reset();
cfg = Service::CFG::GetModule(Core::System::GetInstance());
}
@@ -30,6 +35,7 @@ jboolean Java_org_citra_citra_1emu_utils_SystemSaveGame_getIsSystemSetupNeeded(
void Java_org_citra_citra_1emu_utils_SystemSaveGame_setSystemSetupNeeded(
[[maybe_unused]] JNIEnv* env, [[maybe_unused]] jobject obj, jboolean needed) {
cfg->SetSystemSetupNeeded(needed);
changes_pending = true;
}
jstring Java_org_citra_citra_1emu_utils_SystemSaveGame_getUsername([[maybe_unused]] JNIEnv* env,
@@ -41,6 +47,7 @@ void Java_org_citra_citra_1emu_utils_SystemSaveGame_setUsername([[maybe_unused]]
[[maybe_unused]] jobject obj,
jstring username) {
cfg->SetUsername(Common::UTF8ToUTF16(GetJString(env, username)));
changes_pending = true;
}
jshortArray Java_org_citra_citra_1emu_utils_SystemSaveGame_getBirthday(
@@ -57,6 +64,7 @@ void Java_org_citra_citra_1emu_utils_SystemSaveGame_setBirthday([[maybe_unused]]
[[maybe_unused]] jobject obj,
jshort jmonth, jshort jday) {
cfg->SetBirthday(static_cast<u8>(jmonth), static_cast<u8>(jday));
changes_pending = true;
}
jint Java_org_citra_citra_1emu_utils_SystemSaveGame_getSystemLanguage(
@@ -68,6 +76,7 @@ void Java_org_citra_citra_1emu_utils_SystemSaveGame_setSystemLanguage([[maybe_un
[[maybe_unused]] jobject obj,
jint jsystemLanguage) {
cfg->SetSystemLanguage(static_cast<Service::CFG::SystemLanguage>(jsystemLanguage));
changes_pending = true;
}
jint Java_org_citra_citra_1emu_utils_SystemSaveGame_getSoundOutputMode(
@@ -79,6 +88,7 @@ void Java_org_citra_citra_1emu_utils_SystemSaveGame_setSoundOutputMode([[maybe_u
[[maybe_unused]] jobject obj,
jint jmode) {
cfg->SetSoundOutputMode(static_cast<Service::CFG::SoundOutputMode>(jmode));
changes_pending = true;
}
jshort Java_org_citra_citra_1emu_utils_SystemSaveGame_getCountryCode([[maybe_unused]] JNIEnv* env,
@@ -90,6 +100,7 @@ void Java_org_citra_citra_1emu_utils_SystemSaveGame_setCountryCode([[maybe_unuse
[[maybe_unused]] jobject obj,
jshort jmode) {
cfg->SetCountryCode(static_cast<u8>(jmode));
changes_pending = true;
}
jint Java_org_citra_citra_1emu_utils_SystemSaveGame_getPlayCoins([[maybe_unused]] JNIEnv* env,
@@ -101,6 +112,7 @@ void Java_org_citra_citra_1emu_utils_SystemSaveGame_setPlayCoins([[maybe_unused]
[[maybe_unused]] jobject obj,
jint jcoins) {
Service::PTM::Module::SetPlayCoins(static_cast<u16>(jcoins));
changes_pending = true;
}
jlong Java_org_citra_citra_1emu_utils_SystemSaveGame_getConsoleId([[maybe_unused]] JNIEnv* env,
@@ -112,7 +124,7 @@ void Java_org_citra_citra_1emu_utils_SystemSaveGame_regenerateConsoleId(
[[maybe_unused]] JNIEnv* env, [[maybe_unused]] jobject obj) {
const auto [random_number, console_id] = cfg->GenerateConsoleUniqueId();
cfg->SetConsoleUniqueId(random_number, console_id);
cfg->UpdateConfigNANDSavegame();
changes_pending = true;
}
} // extern "C"

View File

@@ -190,7 +190,7 @@
<string name="steps_per_hour_description">Number of steps per hour reported by the pedometer. Range from 0 to 65,535.</string>
<string name="console_id">Console ID</string>
<string name="regenerate_console_id">Regenerate Console ID</string>
<string name="regenerate_console_id_description">This will replace your current virtual 3DS with a new one. Your current virtual 3DS will not be recoverable. This might have unexpected effects inside applications. This might fail if you use an outdated config save. Continue?</string>
<string name="regenerate_console_id_description">This will replace your current virtual 3DS console ID with a new one. Your current virtual 3DS console ID will not be recoverable. This might have unexpected effects inside applications. This might fail if you use an outdated config save. Continue?</string>
<string name="plugin_loader">3GX Plugin Loader</string>
<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>
@@ -778,5 +778,8 @@
<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 required for online multiplayer, eShop access, etc.</string>
<string name="emulation_settings">Emulation Settings</string>
<string name="profile_settings">Profile Settings</string>
</resources>