// SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include #include #include #include "android_config.h" #include "android_settings.h" #include "common/android/android_common.h" #include "common/android/id_cache.h" #include "common/logging/log.h" #include "common/settings.h" #include "frontend_common/config.h" #include "native.h" std::unique_ptr global_config; std::unique_ptr per_game_config; template Settings::Setting* getSetting(JNIEnv* env, jstring jkey) { auto key = Common::Android::GetJString(env, jkey); auto basic_setting = Settings::values.linkage.by_key[key]; if (basic_setting != 0) { return static_cast*>(basic_setting); } auto basic_android_setting = AndroidSettings::values.linkage.by_key[key]; if (basic_android_setting != 0) { return static_cast*>(basic_android_setting); } LOG_ERROR(Frontend, "[Android Native] Could not find setting - {}", key); return nullptr; } extern "C" { void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_initializeGlobalConfig(JNIEnv* env, jobject obj) { global_config = std::make_unique(); } void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_unloadGlobalConfig(JNIEnv* env, jobject obj) { global_config.reset(); } void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_reloadGlobalConfig(JNIEnv* env, jobject obj) { global_config->AndroidConfig::ReloadAllValues(); } void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_saveGlobalConfig(JNIEnv* env, jobject obj) { global_config->AndroidConfig::SaveAllValues(); } void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_initializePerGameConfig(JNIEnv* env, jobject obj, jstring jprogramId, jstring jfileName) { auto program_id = EmulationSession::GetProgramId(env, jprogramId); auto file_name = Common::Android::GetJString(env, jfileName); const auto config_file_name = program_id == 0 ? file_name : fmt::format("{:016X}", program_id); per_game_config = std::make_unique(config_file_name, Config::ConfigType::PerGameConfig); } jboolean Java_org_yuzu_yuzu_1emu_utils_NativeConfig_isPerGameConfigLoaded(JNIEnv* env, jobject obj) { return per_game_config != nullptr; } void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_savePerGameConfig(JNIEnv* env, jobject obj) { per_game_config->AndroidConfig::SaveAllValues(); } void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_unloadPerGameConfig(JNIEnv* env, jobject obj) { per_game_config.reset(); } jboolean Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getBoolean(JNIEnv* env, jobject obj, jstring jkey, jboolean needGlobal) { auto setting = getSetting(env, jkey); if (setting == nullptr) { return false; } return setting->GetValue(static_cast(needGlobal)); } void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setBoolean(JNIEnv* env, jobject obj, jstring jkey, jboolean value) { auto setting = getSetting(env, jkey); if (setting == nullptr) { return; } setting->SetValue(static_cast(value)); } jbyte Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getByte(JNIEnv* env, jobject obj, jstring jkey, jboolean needGlobal) { auto setting = getSetting(env, jkey); if (setting == nullptr) { return -1; } return setting->GetValue(static_cast(needGlobal)); } void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setByte(JNIEnv* env, jobject obj, jstring jkey, jbyte value) { auto setting = getSetting(env, jkey); if (setting == nullptr) { return; } setting->SetValue(value); } jshort Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getShort(JNIEnv* env, jobject obj, jstring jkey, jboolean needGlobal) { auto setting = getSetting(env, jkey); if (setting == nullptr) { return -1; } return setting->GetValue(static_cast(needGlobal)); } void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setShort(JNIEnv* env, jobject obj, jstring jkey, jshort value) { auto setting = getSetting(env, jkey); if (setting == nullptr) { return; } setting->SetValue(value); } jint Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getInt(JNIEnv* env, jobject obj, jstring jkey, jboolean needGlobal) { auto setting = getSetting(env, jkey); if (setting == nullptr) { return -1; } return setting->GetValue(needGlobal); } void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setInt(JNIEnv* env, jobject obj, jstring jkey, jint value) { auto setting = getSetting(env, jkey); if (setting == nullptr) { return; } setting->SetValue(value); } jfloat Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getFloat(JNIEnv* env, jobject obj, jstring jkey, jboolean needGlobal) { auto setting = getSetting(env, jkey); if (setting == nullptr) { return -1; } return setting->GetValue(static_cast(needGlobal)); } void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setFloat(JNIEnv* env, jobject obj, jstring jkey, jfloat value) { auto setting = getSetting(env, jkey); if (setting == nullptr) { return; } setting->SetValue(value); } jlong Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getLong(JNIEnv* env, jobject obj, jstring jkey, jboolean needGlobal) { auto setting = getSetting(env, jkey); if (setting == nullptr) { return -1; } return setting->GetValue(static_cast(needGlobal)); } void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setLong(JNIEnv* env, jobject obj, jstring jkey, jlong value) { auto setting = getSetting(env, jkey); if (setting == nullptr) { return; } setting->SetValue(value); } jstring Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getString(JNIEnv* env, jobject obj, jstring jkey, jboolean needGlobal) { auto setting = getSetting(env, jkey); if (setting == nullptr) { return Common::Android::ToJString(env, ""); } return Common::Android::ToJString(env, setting->GetValue(static_cast(needGlobal))); } void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setString(JNIEnv* env, jobject obj, jstring jkey, jstring value) { auto setting = getSetting(env, jkey); if (setting == nullptr) { return; } setting->SetValue(Common::Android::GetJString(env, value)); } jboolean Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getIsRuntimeModifiable(JNIEnv* env, jobject obj, jstring jkey) { auto setting = getSetting(env, jkey); if (setting != nullptr) { return setting->RuntimeModifiable(); } return true; } jstring Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getPairedSettingKey(JNIEnv* env, jobject obj, jstring jkey) { auto setting = getSetting(env, jkey); if (setting == nullptr) { return Common::Android::ToJString(env, ""); } if (setting->PairedSetting() == nullptr) { return Common::Android::ToJString(env, ""); } return Common::Android::ToJString(env, setting->PairedSetting()->GetLabel()); } jboolean Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getIsSwitchable(JNIEnv* env, jobject obj, jstring jkey) { auto setting = getSetting(env, jkey); if (setting != nullptr) { return setting->Switchable(); } return false; } jboolean Java_org_yuzu_yuzu_1emu_utils_NativeConfig_usingGlobal(JNIEnv* env, jobject obj, jstring jkey) { auto setting = getSetting(env, jkey); if (setting != nullptr) { return setting->UsingGlobal(); } return true; } void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setGlobal(JNIEnv* env, jobject obj, jstring jkey, jboolean global) { auto setting = getSetting(env, jkey); if (setting != nullptr) { setting->SetGlobal(static_cast(global)); } } jboolean Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getIsSaveable(JNIEnv* env, jobject obj, jstring jkey) { auto setting = getSetting(env, jkey); if (setting != nullptr) { return setting->Save(); } return false; } jstring Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getDefaultToString(JNIEnv* env, jobject obj, jstring jkey) { auto setting = getSetting(env, jkey); if (setting != nullptr) { return Common::Android::ToJString(env, setting->DefaultToString()); } return Common::Android::ToJString(env, ""); } jobjectArray Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getGameDirs(JNIEnv* env, jobject obj) { jclass gameDirClass = Common::Android::GetGameDirClass(); jmethodID gameDirConstructor = Common::Android::GetGameDirConstructor(); jobjectArray jgameDirArray = env->NewObjectArray(AndroidSettings::values.game_dirs.size(), gameDirClass, nullptr); for (size_t i = 0; i < AndroidSettings::values.game_dirs.size(); ++i) { jobject jgameDir = env->NewObject( gameDirClass, gameDirConstructor, Common::Android::ToJString(env, AndroidSettings::values.game_dirs[i].path), static_cast(AndroidSettings::values.game_dirs[i].deep_scan)); env->SetObjectArrayElement(jgameDirArray, i, jgameDir); } return jgameDirArray; } void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setGameDirs(JNIEnv* env, jobject obj, jobjectArray gameDirs) { AndroidSettings::values.game_dirs.clear(); int size = env->GetArrayLength(gameDirs); if (size == 0) { return; } jobject dir = env->GetObjectArrayElement(gameDirs, 0); jclass gameDirClass = Common::Android::GetGameDirClass(); jfieldID uriStringField = env->GetFieldID(gameDirClass, "uriString", "Ljava/lang/String;"); jfieldID deepScanBooleanField = env->GetFieldID(gameDirClass, "deepScan", "Z"); for (int i = 0; i < size; ++i) { dir = env->GetObjectArrayElement(gameDirs, i); jstring juriString = static_cast(env->GetObjectField(dir, uriStringField)); jboolean jdeepScanBoolean = env->GetBooleanField(dir, deepScanBooleanField); std::string uriString = Common::Android::GetJString(env, juriString); AndroidSettings::values.game_dirs.push_back( AndroidSettings::GameDir{uriString, static_cast(jdeepScanBoolean)}); } } void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_addGameDir(JNIEnv* env, jobject obj, jobject gameDir) { jclass gameDirClass = Common::Android::GetGameDirClass(); jfieldID uriStringField = env->GetFieldID(gameDirClass, "uriString", "Ljava/lang/String;"); jfieldID deepScanBooleanField = env->GetFieldID(gameDirClass, "deepScan", "Z"); jstring juriString = static_cast(env->GetObjectField(gameDir, uriStringField)); jboolean jdeepScanBoolean = env->GetBooleanField(gameDir, deepScanBooleanField); std::string uriString = Common::Android::GetJString(env, juriString); AndroidSettings::values.game_dirs.push_back( AndroidSettings::GameDir{uriString, static_cast(jdeepScanBoolean)}); } jobjectArray Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getDisabledAddons(JNIEnv* env, jobject obj, jstring jprogramId) { auto program_id = EmulationSession::GetProgramId(env, jprogramId); auto& disabledAddons = Settings::values.disabled_addons[program_id]; jobjectArray jdisabledAddonsArray = env->NewObjectArray(disabledAddons.size(), Common::Android::GetStringClass(), Common::Android::ToJString(env, "")); for (size_t i = 0; i < disabledAddons.size(); ++i) { env->SetObjectArrayElement(jdisabledAddonsArray, i, Common::Android::ToJString(env, disabledAddons[i])); } return jdisabledAddonsArray; } void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setDisabledAddons(JNIEnv* env, jobject obj, jstring jprogramId, jobjectArray jdisabledAddons) { auto program_id = EmulationSession::GetProgramId(env, jprogramId); Settings::values.disabled_addons[program_id].clear(); std::vector disabled_addons; const int size = env->GetArrayLength(jdisabledAddons); for (int i = 0; i < size; ++i) { auto jaddon = static_cast(env->GetObjectArrayElement(jdisabledAddons, i)); disabled_addons.push_back(Common::Android::GetJString(env, jaddon)); } Settings::values.disabled_addons[program_id] = disabled_addons; } jobjectArray Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getOverlayControlData(JNIEnv* env, jobject obj) { jobjectArray joverlayControlDataArray = env->NewObjectArray(AndroidSettings::values.overlay_control_data.size(), Common::Android::GetOverlayControlDataClass(), nullptr); for (size_t i = 0; i < AndroidSettings::values.overlay_control_data.size(); ++i) { const auto& control_data = AndroidSettings::values.overlay_control_data[i]; jobject jlandscapePosition = env->NewObject(Common::Android::GetPairClass(), Common::Android::GetPairConstructor(), Common::Android::ToJDouble(env, control_data.landscape_position.first), Common::Android::ToJDouble(env, control_data.landscape_position.second)); jobject jportraitPosition = env->NewObject(Common::Android::GetPairClass(), Common::Android::GetPairConstructor(), Common::Android::ToJDouble(env, control_data.portrait_position.first), Common::Android::ToJDouble(env, control_data.portrait_position.second)); jobject jfoldablePosition = env->NewObject(Common::Android::GetPairClass(), Common::Android::GetPairConstructor(), Common::Android::ToJDouble(env, control_data.foldable_position.first), Common::Android::ToJDouble(env, control_data.foldable_position.second)); jobject jcontrolData = env->NewObject(Common::Android::GetOverlayControlDataClass(), Common::Android::GetOverlayControlDataConstructor(), Common::Android::ToJString(env, control_data.id), control_data.enabled, jlandscapePosition, jportraitPosition, jfoldablePosition); env->SetObjectArrayElement(joverlayControlDataArray, i, jcontrolData); } return joverlayControlDataArray; } void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setOverlayControlData( JNIEnv* env, jobject obj, jobjectArray joverlayControlDataArray) { AndroidSettings::values.overlay_control_data.clear(); int size = env->GetArrayLength(joverlayControlDataArray); if (size == 0) { return; } for (int i = 0; i < size; ++i) { jobject joverlayControlData = env->GetObjectArrayElement(joverlayControlDataArray, i); jstring jidString = static_cast(env->GetObjectField( joverlayControlData, Common::Android::GetOverlayControlDataIdField())); bool enabled = static_cast(env->GetBooleanField( joverlayControlData, Common::Android::GetOverlayControlDataEnabledField())); jobject jlandscapePosition = env->GetObjectField( joverlayControlData, Common::Android::GetOverlayControlDataLandscapePositionField()); std::pair landscape_position = std::make_pair( Common::Android::GetJDouble( env, env->GetObjectField(jlandscapePosition, Common::Android::GetPairFirstField())), Common::Android::GetJDouble( env, env->GetObjectField(jlandscapePosition, Common::Android::GetPairSecondField()))); jobject jportraitPosition = env->GetObjectField( joverlayControlData, Common::Android::GetOverlayControlDataPortraitPositionField()); std::pair portrait_position = std::make_pair( Common::Android::GetJDouble( env, env->GetObjectField(jportraitPosition, Common::Android::GetPairFirstField())), Common::Android::GetJDouble( env, env->GetObjectField(jportraitPosition, Common::Android::GetPairSecondField()))); jobject jfoldablePosition = env->GetObjectField( joverlayControlData, Common::Android::GetOverlayControlDataFoldablePositionField()); std::pair foldable_position = std::make_pair( Common::Android::GetJDouble( env, env->GetObjectField(jfoldablePosition, Common::Android::GetPairFirstField())), Common::Android::GetJDouble( env, env->GetObjectField(jfoldablePosition, Common::Android::GetPairSecondField()))); AndroidSettings::values.overlay_control_data.push_back(AndroidSettings::OverlayControlData{ Common::Android::GetJString(env, jidString), enabled, landscape_position, portrait_position, foldable_position}); } } } // extern "C"