Browse Source

android: Refactor settings to expose more options

In AbstractSetting, this removes the category, androidDefault, and valueAsString properties as they are no longer needed and have replacements. isSwitchable, global, and getValueAsString are all exposed and give better options for working with global/per-game settings.
t895 2 years ago
parent
commit
70c3d36536
34 changed files with 324 additions and 353 deletions
  1. 13 7
      src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt
  2. 1 2
      src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractBooleanSetting.kt
  3. 1 2
      src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractByteSetting.kt
  4. 1 2
      src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractFloatSetting.kt
  5. 1 2
      src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractIntSetting.kt
  6. 1 2
      src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractLongSetting.kt
  7. 9 5
      src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractSetting.kt
  8. 1 2
      src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractShortSetting.kt
  9. 1 2
      src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractStringSetting.kt
  10. 26 28
      src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt
  11. 11 11
      src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/ByteSetting.kt
  12. 11 11
      src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/FloatSetting.kt
  13. 25 28
      src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt
  14. 11 11
      src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/LongSetting.kt
  15. 0 51
      src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt
  16. 11 11
      src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/ShortSetting.kt
  17. 11 12
      src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/StringSetting.kt
  18. 2 3
      src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/DateTimeSetting.kt
  19. 18 6
      src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt
  20. 6 11
      src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SingleChoiceSetting.kt
  21. 14 16
      src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SliderSetting.kt
  22. 3 4
      src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/StringSingleChoiceSetting.kt
  23. 12 12
      src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SwitchSetting.kt
  24. 6 5
      src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt
  25. 19 10
      src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt
  26. 1 1
      src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt
  27. 2 2
      src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SingleChoiceViewHolder.kt
  28. 1 1
      src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SliderViewHolder.kt
  29. 1 1
      src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt
  30. 3 3
      src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
  31. 6 6
      src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SettingsDialogFragment.kt
  32. 39 8
      src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/NativeConfig.kt
  33. 52 74
      src/android/app/src/main/jni/native_config.cpp
  34. 4 1
      src/common/settings_setting.h

+ 13 - 7
src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt

@@ -172,7 +172,7 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
 
 
     override fun onUserLeaveHint() {
     override fun onUserLeaveHint() {
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
-            if (BooleanSetting.PICTURE_IN_PICTURE.boolean && !isInPictureInPictureMode) {
+            if (BooleanSetting.PICTURE_IN_PICTURE.getBoolean() && !isInPictureInPictureMode) {
                 val pictureInPictureParamsBuilder = PictureInPictureParams.Builder()
                 val pictureInPictureParamsBuilder = PictureInPictureParams.Builder()
                     .getPictureInPictureActionsBuilder().getPictureInPictureAspectBuilder()
                     .getPictureInPictureActionsBuilder().getPictureInPictureAspectBuilder()
                 enterPictureInPictureMode(pictureInPictureParamsBuilder.build())
                 enterPictureInPictureMode(pictureInPictureParamsBuilder.build())
@@ -284,7 +284,7 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
 
 
     private fun PictureInPictureParams.Builder.getPictureInPictureAspectBuilder():
     private fun PictureInPictureParams.Builder.getPictureInPictureAspectBuilder():
         PictureInPictureParams.Builder {
         PictureInPictureParams.Builder {
-        val aspectRatio = when (IntSetting.RENDERER_ASPECT_RATIO.int) {
+        val aspectRatio = when (IntSetting.RENDERER_ASPECT_RATIO.getInt()) {
             0 -> Rational(16, 9)
             0 -> Rational(16, 9)
             1 -> Rational(4, 3)
             1 -> Rational(4, 3)
             2 -> Rational(21, 9)
             2 -> Rational(21, 9)
@@ -331,7 +331,7 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
             pictureInPictureActions.add(pauseRemoteAction)
             pictureInPictureActions.add(pauseRemoteAction)
         }
         }
 
 
-        if (BooleanSetting.AUDIO_MUTED.boolean) {
+        if (BooleanSetting.AUDIO_MUTED.getBoolean()) {
             val unmuteIcon = Icon.createWithResource(
             val unmuteIcon = Icon.createWithResource(
                 this@EmulationActivity,
                 this@EmulationActivity,
                 R.drawable.ic_pip_unmute
                 R.drawable.ic_pip_unmute
@@ -376,7 +376,7 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
             val isEmulationActive = emulationViewModel.emulationStarted.value &&
             val isEmulationActive = emulationViewModel.emulationStarted.value &&
                 !emulationViewModel.isEmulationStopping.value
                 !emulationViewModel.isEmulationStopping.value
             pictureInPictureParamsBuilder.setAutoEnterEnabled(
             pictureInPictureParamsBuilder.setAutoEnterEnabled(
-                BooleanSetting.PICTURE_IN_PICTURE.boolean && isEmulationActive
+                BooleanSetting.PICTURE_IN_PICTURE.getBoolean() && isEmulationActive
             )
             )
         }
         }
         setPictureInPictureParams(pictureInPictureParamsBuilder.build())
         setPictureInPictureParams(pictureInPictureParamsBuilder.build())
@@ -390,9 +390,13 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
                 if (!NativeLibrary.isPaused()) NativeLibrary.pauseEmulation()
                 if (!NativeLibrary.isPaused()) NativeLibrary.pauseEmulation()
             }
             }
             if (intent.action == actionUnmute) {
             if (intent.action == actionUnmute) {
-                if (BooleanSetting.AUDIO_MUTED.boolean) BooleanSetting.AUDIO_MUTED.setBoolean(false)
+                if (BooleanSetting.AUDIO_MUTED.getBoolean()) {
+                    BooleanSetting.AUDIO_MUTED.setBoolean(false)
+                }
             } else if (intent.action == actionMute) {
             } else if (intent.action == actionMute) {
-                if (!BooleanSetting.AUDIO_MUTED.boolean) BooleanSetting.AUDIO_MUTED.setBoolean(true)
+                if (!BooleanSetting.AUDIO_MUTED.getBoolean()) {
+                    BooleanSetting.AUDIO_MUTED.setBoolean(true)
+                }
             }
             }
             buildPictureInPictureParams()
             buildPictureInPictureParams()
         }
         }
@@ -423,7 +427,9 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
             } catch (ignored: Exception) {
             } catch (ignored: Exception) {
             }
             }
             // Always resume audio, since there is no UI button
             // Always resume audio, since there is no UI button
-            if (BooleanSetting.AUDIO_MUTED.boolean) BooleanSetting.AUDIO_MUTED.setBoolean(false)
+            if (BooleanSetting.AUDIO_MUTED.getBoolean()) {
+                BooleanSetting.AUDIO_MUTED.setBoolean(false)
+            }
         }
         }
     }
     }
 
 

+ 1 - 2
src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractBooleanSetting.kt

@@ -4,7 +4,6 @@
 package org.yuzu.yuzu_emu.features.settings.model
 package org.yuzu.yuzu_emu.features.settings.model
 
 
 interface AbstractBooleanSetting : AbstractSetting {
 interface AbstractBooleanSetting : AbstractSetting {
-    val boolean: Boolean
-
+    fun getBoolean(needsGlobal: Boolean = false): Boolean
     fun setBoolean(value: Boolean)
     fun setBoolean(value: Boolean)
 }
 }

+ 1 - 2
src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractByteSetting.kt

@@ -4,7 +4,6 @@
 package org.yuzu.yuzu_emu.features.settings.model
 package org.yuzu.yuzu_emu.features.settings.model
 
 
 interface AbstractByteSetting : AbstractSetting {
 interface AbstractByteSetting : AbstractSetting {
-    val byte: Byte
-
+    fun getByte(needsGlobal: Boolean = false): Byte
     fun setByte(value: Byte)
     fun setByte(value: Byte)
 }
 }

+ 1 - 2
src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractFloatSetting.kt

@@ -4,7 +4,6 @@
 package org.yuzu.yuzu_emu.features.settings.model
 package org.yuzu.yuzu_emu.features.settings.model
 
 
 interface AbstractFloatSetting : AbstractSetting {
 interface AbstractFloatSetting : AbstractSetting {
-    val float: Float
-
+    fun getFloat(needsGlobal: Boolean = false): Float
     fun setFloat(value: Float)
     fun setFloat(value: Float)
 }
 }

+ 1 - 2
src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractIntSetting.kt

@@ -4,7 +4,6 @@
 package org.yuzu.yuzu_emu.features.settings.model
 package org.yuzu.yuzu_emu.features.settings.model
 
 
 interface AbstractIntSetting : AbstractSetting {
 interface AbstractIntSetting : AbstractSetting {
-    val int: Int
-
+    fun getInt(needsGlobal: Boolean = false): Int
     fun setInt(value: Int)
     fun setInt(value: Int)
 }
 }

+ 1 - 2
src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractLongSetting.kt

@@ -4,7 +4,6 @@
 package org.yuzu.yuzu_emu.features.settings.model
 package org.yuzu.yuzu_emu.features.settings.model
 
 
 interface AbstractLongSetting : AbstractSetting {
 interface AbstractLongSetting : AbstractSetting {
-    val long: Long
-
+    fun getLong(needsGlobal: Boolean = false): Long
     fun setLong(value: Long)
     fun setLong(value: Long)
 }
 }

+ 9 - 5
src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractSetting.kt

@@ -7,12 +7,7 @@ import org.yuzu.yuzu_emu.utils.NativeConfig
 
 
 interface AbstractSetting {
 interface AbstractSetting {
     val key: String
     val key: String
-    val category: Settings.Category
     val defaultValue: Any
     val defaultValue: Any
-    val androidDefault: Any?
-        get() = null
-    val valueAsString: String
-        get() = ""
 
 
     val isRuntimeModifiable: Boolean
     val isRuntimeModifiable: Boolean
         get() = NativeConfig.getIsRuntimeModifiable(key)
         get() = NativeConfig.getIsRuntimeModifiable(key)
@@ -20,5 +15,14 @@ interface AbstractSetting {
     val pairedSettingKey: String
     val pairedSettingKey: String
         get() = NativeConfig.getPairedSettingKey(key)
         get() = NativeConfig.getPairedSettingKey(key)
 
 
+    val isSwitchable: Boolean
+        get() = NativeConfig.getIsSwitchable(key)
+
+    var global: Boolean
+        get() = NativeConfig.usingGlobal(key)
+        set(value) = NativeConfig.setGlobal(key, value)
+
+    fun getValueAsString(needsGlobal: Boolean = false): String
+
     fun reset()
     fun reset()
 }
 }

+ 1 - 2
src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractShortSetting.kt

@@ -4,7 +4,6 @@
 package org.yuzu.yuzu_emu.features.settings.model
 package org.yuzu.yuzu_emu.features.settings.model
 
 
 interface AbstractShortSetting : AbstractSetting {
 interface AbstractShortSetting : AbstractSetting {
-    val short: Short
-
+    fun getShort(needsGlobal: Boolean = false): Short
     fun setShort(value: Short)
     fun setShort(value: Short)
 }
 }

+ 1 - 2
src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractStringSetting.kt

@@ -4,7 +4,6 @@
 package org.yuzu.yuzu_emu.features.settings.model
 package org.yuzu.yuzu_emu.features.settings.model
 
 
 interface AbstractStringSetting : AbstractSetting {
 interface AbstractStringSetting : AbstractSetting {
-    val string: String
-
+    fun getString(needsGlobal: Boolean = false): String
     fun setString(value: String)
     fun setString(value: String)
 }
 }

+ 26 - 28
src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt

@@ -5,36 +5,34 @@ package org.yuzu.yuzu_emu.features.settings.model
 
 
 import org.yuzu.yuzu_emu.utils.NativeConfig
 import org.yuzu.yuzu_emu.utils.NativeConfig
 
 
-enum class BooleanSetting(
-    override val key: String,
-    override val category: Settings.Category,
-    override val androidDefault: Boolean? = null
-) : AbstractBooleanSetting {
-    AUDIO_MUTED("audio_muted", Settings.Category.Audio),
-    CPU_DEBUG_MODE("cpu_debug_mode", Settings.Category.Cpu),
-    FASTMEM("cpuopt_fastmem", Settings.Category.Cpu),
-    FASTMEM_EXCLUSIVES("cpuopt_fastmem_exclusives", Settings.Category.Cpu),
-    RENDERER_USE_SPEED_LIMIT("use_speed_limit", Settings.Category.Core),
-    USE_DOCKED_MODE("use_docked_mode", Settings.Category.System, false),
-    RENDERER_USE_DISK_SHADER_CACHE("use_disk_shader_cache", Settings.Category.Renderer),
-    RENDERER_FORCE_MAX_CLOCK("force_max_clock", Settings.Category.Renderer),
-    RENDERER_ASYNCHRONOUS_SHADERS("use_asynchronous_shaders", Settings.Category.Renderer),
-    RENDERER_REACTIVE_FLUSHING("use_reactive_flushing", Settings.Category.Renderer, false),
-    RENDERER_DEBUG("debug", Settings.Category.Renderer),
-    PICTURE_IN_PICTURE("picture_in_picture", Settings.Category.Android),
-    USE_CUSTOM_RTC("custom_rtc_enabled", Settings.Category.System);
-
-    override val boolean: Boolean
-        get() = NativeConfig.getBoolean(key, false)
-
-    override fun setBoolean(value: Boolean) = NativeConfig.setBoolean(key, value)
-
-    override val defaultValue: Boolean by lazy {
-        androidDefault ?: NativeConfig.getBoolean(key, true)
+enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
+    AUDIO_MUTED("audio_muted"),
+    CPU_DEBUG_MODE("cpu_debug_mode"),
+    FASTMEM("cpuopt_fastmem"),
+    FASTMEM_EXCLUSIVES("cpuopt_fastmem_exclusives"),
+    RENDERER_USE_SPEED_LIMIT("use_speed_limit"),
+    USE_DOCKED_MODE("use_docked_mode"),
+    RENDERER_USE_DISK_SHADER_CACHE("use_disk_shader_cache"),
+    RENDERER_FORCE_MAX_CLOCK("force_max_clock"),
+    RENDERER_ASYNCHRONOUS_SHADERS("use_asynchronous_shaders"),
+    RENDERER_REACTIVE_FLUSHING("use_reactive_flushing"),
+    RENDERER_DEBUG("debug"),
+    PICTURE_IN_PICTURE("picture_in_picture"),
+    USE_CUSTOM_RTC("custom_rtc_enabled");
+
+    override fun getBoolean(needsGlobal: Boolean): Boolean =
+        NativeConfig.getBoolean(key, needsGlobal)
+
+    override fun setBoolean(value: Boolean) {
+        if (NativeConfig.isPerGameConfigLoaded()) {
+            global = false
+        }
+        NativeConfig.setBoolean(key, value)
     }
     }
 
 
-    override val valueAsString: String
-        get() = if (boolean) "1" else "0"
+    override val defaultValue: Boolean by lazy { NativeConfig.getDefaultToString(key).toBoolean() }
+
+    override fun getValueAsString(needsGlobal: Boolean): String = getBoolean(needsGlobal).toString()
 
 
     override fun reset() = NativeConfig.setBoolean(key, defaultValue)
     override fun reset() = NativeConfig.setBoolean(key, defaultValue)
 }
 }

+ 11 - 11
src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/ByteSetting.kt

@@ -5,21 +5,21 @@ package org.yuzu.yuzu_emu.features.settings.model
 
 
 import org.yuzu.yuzu_emu.utils.NativeConfig
 import org.yuzu.yuzu_emu.utils.NativeConfig
 
 
-enum class ByteSetting(
-    override val key: String,
-    override val category: Settings.Category
-) : AbstractByteSetting {
-    AUDIO_VOLUME("volume", Settings.Category.Audio);
+enum class ByteSetting(override val key: String) : AbstractByteSetting {
+    AUDIO_VOLUME("volume");
 
 
-    override val byte: Byte
-        get() = NativeConfig.getByte(key, false)
+    override fun getByte(needsGlobal: Boolean): Byte = NativeConfig.getByte(key, needsGlobal)
 
 
-    override fun setByte(value: Byte) = NativeConfig.setByte(key, value)
+    override fun setByte(value: Byte) {
+        if (NativeConfig.isPerGameConfigLoaded()) {
+            global = false
+        }
+        NativeConfig.setByte(key, value)
+    }
 
 
-    override val defaultValue: Byte by lazy { NativeConfig.getByte(key, true) }
+    override val defaultValue: Byte by lazy { NativeConfig.getDefaultToString(key).toByte() }
 
 
-    override val valueAsString: String
-        get() = byte.toString()
+    override fun getValueAsString(needsGlobal: Boolean): String = getByte(needsGlobal).toString()
 
 
     override fun reset() = NativeConfig.setByte(key, defaultValue)
     override fun reset() = NativeConfig.setByte(key, defaultValue)
 }
 }

+ 11 - 11
src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/FloatSetting.kt

@@ -5,22 +5,22 @@ package org.yuzu.yuzu_emu.features.settings.model
 
 
 import org.yuzu.yuzu_emu.utils.NativeConfig
 import org.yuzu.yuzu_emu.utils.NativeConfig
 
 
-enum class FloatSetting(
-    override val key: String,
-    override val category: Settings.Category
-) : AbstractFloatSetting {
+enum class FloatSetting(override val key: String) : AbstractFloatSetting {
     // No float settings currently exist
     // No float settings currently exist
-    EMPTY_SETTING("", Settings.Category.UiGeneral);
+    EMPTY_SETTING("");
 
 
-    override val float: Float
-        get() = NativeConfig.getFloat(key, false)
+    override fun getFloat(needsGlobal: Boolean): Float = NativeConfig.getFloat(key, false)
 
 
-    override fun setFloat(value: Float) = NativeConfig.setFloat(key, value)
+    override fun setFloat(value: Float) {
+        if (NativeConfig.isPerGameConfigLoaded()) {
+            global = false
+        }
+        NativeConfig.setFloat(key, value)
+    }
 
 
-    override val defaultValue: Float by lazy { NativeConfig.getFloat(key, true) }
+    override val defaultValue: Float by lazy { NativeConfig.getDefaultToString(key).toFloat() }
 
 
-    override val valueAsString: String
-        get() = float.toString()
+    override fun getValueAsString(needsGlobal: Boolean): String = getFloat(needsGlobal).toString()
 
 
     override fun reset() = NativeConfig.setFloat(key, defaultValue)
     override fun reset() = NativeConfig.setFloat(key, defaultValue)
 }
 }

+ 25 - 28
src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt

@@ -5,36 +5,33 @@ package org.yuzu.yuzu_emu.features.settings.model
 
 
 import org.yuzu.yuzu_emu.utils.NativeConfig
 import org.yuzu.yuzu_emu.utils.NativeConfig
 
 
-enum class IntSetting(
-    override val key: String,
-    override val category: Settings.Category,
-    override val androidDefault: Int? = null
-) : AbstractIntSetting {
-    CPU_BACKEND("cpu_backend", Settings.Category.Cpu),
-    CPU_ACCURACY("cpu_accuracy", Settings.Category.Cpu),
-    REGION_INDEX("region_index", Settings.Category.System),
-    LANGUAGE_INDEX("language_index", Settings.Category.System),
-    RENDERER_BACKEND("backend", Settings.Category.Renderer),
-    RENDERER_ACCURACY("gpu_accuracy", Settings.Category.Renderer, 0),
-    RENDERER_RESOLUTION("resolution_setup", Settings.Category.Renderer),
-    RENDERER_VSYNC("use_vsync", Settings.Category.Renderer),
-    RENDERER_SCALING_FILTER("scaling_filter", Settings.Category.Renderer),
-    RENDERER_ANTI_ALIASING("anti_aliasing", Settings.Category.Renderer),
-    RENDERER_SCREEN_LAYOUT("screen_layout", Settings.Category.Android),
-    RENDERER_ASPECT_RATIO("aspect_ratio", Settings.Category.Renderer),
-    AUDIO_OUTPUT_ENGINE("output_engine", Settings.Category.Audio);
-
-    override val int: Int
-        get() = NativeConfig.getInt(key, false)
-
-    override fun setInt(value: Int) = NativeConfig.setInt(key, value)
-
-    override val defaultValue: Int by lazy {
-        androidDefault ?: NativeConfig.getInt(key, true)
+enum class IntSetting(override val key: String) : AbstractIntSetting {
+    CPU_BACKEND("cpu_backend"),
+    CPU_ACCURACY("cpu_accuracy"),
+    REGION_INDEX("region_index"),
+    LANGUAGE_INDEX("language_index"),
+    RENDERER_BACKEND("backend"),
+    RENDERER_ACCURACY("gpu_accuracy"),
+    RENDERER_RESOLUTION("resolution_setup"),
+    RENDERER_VSYNC("use_vsync"),
+    RENDERER_SCALING_FILTER("scaling_filter"),
+    RENDERER_ANTI_ALIASING("anti_aliasing"),
+    RENDERER_SCREEN_LAYOUT("screen_layout"),
+    RENDERER_ASPECT_RATIO("aspect_ratio"),
+    AUDIO_OUTPUT_ENGINE("output_engine");
+
+    override fun getInt(needsGlobal: Boolean): Int = NativeConfig.getInt(key, needsGlobal)
+
+    override fun setInt(value: Int) {
+        if (NativeConfig.isPerGameConfigLoaded()) {
+            global = false
+        }
+        NativeConfig.setInt(key, value)
     }
     }
 
 
-    override val valueAsString: String
-        get() = int.toString()
+    override val defaultValue: Int by lazy { NativeConfig.getDefaultToString(key).toInt() }
+
+    override fun getValueAsString(needsGlobal: Boolean): String = getInt(needsGlobal).toString()
 
 
     override fun reset() = NativeConfig.setInt(key, defaultValue)
     override fun reset() = NativeConfig.setInt(key, defaultValue)
 }
 }

+ 11 - 11
src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/LongSetting.kt

@@ -5,21 +5,21 @@ package org.yuzu.yuzu_emu.features.settings.model
 
 
 import org.yuzu.yuzu_emu.utils.NativeConfig
 import org.yuzu.yuzu_emu.utils.NativeConfig
 
 
-enum class LongSetting(
-    override val key: String,
-    override val category: Settings.Category
-) : AbstractLongSetting {
-    CUSTOM_RTC("custom_rtc", Settings.Category.System);
+enum class LongSetting(override val key: String) : AbstractLongSetting {
+    CUSTOM_RTC("custom_rtc");
 
 
-    override val long: Long
-        get() = NativeConfig.getLong(key, false)
+    override fun getLong(needsGlobal: Boolean): Long = NativeConfig.getLong(key, needsGlobal)
 
 
-    override fun setLong(value: Long) = NativeConfig.setLong(key, value)
+    override fun setLong(value: Long) {
+        if (NativeConfig.isPerGameConfigLoaded()) {
+            global = false
+        }
+        NativeConfig.setLong(key, value)
+    }
 
 
-    override val defaultValue: Long by lazy { NativeConfig.getLong(key, true) }
+    override val defaultValue: Long by lazy { NativeConfig.getDefaultToString(key).toLong() }
 
 
-    override val valueAsString: String
-        get() = long.toString()
+    override fun getValueAsString(needsGlobal: Boolean): String = getLong(needsGlobal).toString()
 
 
     override fun reset() = NativeConfig.setLong(key, defaultValue)
     override fun reset() = NativeConfig.setLong(key, defaultValue)
 }
 }

+ 0 - 51
src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt

@@ -6,62 +6,11 @@ package org.yuzu.yuzu_emu.features.settings.model
 import org.yuzu.yuzu_emu.R
 import org.yuzu.yuzu_emu.R
 
 
 object Settings {
 object Settings {
-    enum class Category {
-        Android,
-        Audio,
-        Core,
-        Cpu,
-        CpuDebug,
-        CpuUnsafe,
-        Renderer,
-        RendererAdvanced,
-        RendererDebug,
-        System,
-        SystemAudio,
-        DataStorage,
-        Debugging,
-        DebuggingGraphics,
-        Miscellaneous,
-        Network,
-        WebService,
-        AddOns,
-        Controls,
-        Ui,
-        UiGeneral,
-        UiLayout,
-        UiGameList,
-        Screenshots,
-        Shortcuts,
-        Multiplayer,
-        Services,
-        Paths,
-        MaxEnum
-    }
-
-    val settingsList = listOf<AbstractSetting>(
-        *BooleanSetting.values(),
-        *ByteSetting.values(),
-        *ShortSetting.values(),
-        *IntSetting.values(),
-        *FloatSetting.values(),
-        *LongSetting.values(),
-        *StringSetting.values()
-    )
-
-    const val SECTION_GENERAL = "General"
-    const val SECTION_SYSTEM = "System"
-    const val SECTION_RENDERER = "Renderer"
-    const val SECTION_AUDIO = "Audio"
-    const val SECTION_CPU = "Cpu"
-    const val SECTION_THEME = "Theme"
-    const val SECTION_DEBUG = "Debug"
-
     enum class MenuTag(val titleId: Int) {
     enum class MenuTag(val titleId: Int) {
         SECTION_ROOT(R.string.advanced_settings),
         SECTION_ROOT(R.string.advanced_settings),
         SECTION_SYSTEM(R.string.preferences_system),
         SECTION_SYSTEM(R.string.preferences_system),
         SECTION_RENDERER(R.string.preferences_graphics),
         SECTION_RENDERER(R.string.preferences_graphics),
         SECTION_AUDIO(R.string.preferences_audio),
         SECTION_AUDIO(R.string.preferences_audio),
-        SECTION_CPU(R.string.cpu),
         SECTION_THEME(R.string.preferences_theme),
         SECTION_THEME(R.string.preferences_theme),
         SECTION_DEBUG(R.string.preferences_debug);
         SECTION_DEBUG(R.string.preferences_debug);
     }
     }

+ 11 - 11
src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/ShortSetting.kt

@@ -5,21 +5,21 @@ package org.yuzu.yuzu_emu.features.settings.model
 
 
 import org.yuzu.yuzu_emu.utils.NativeConfig
 import org.yuzu.yuzu_emu.utils.NativeConfig
 
 
-enum class ShortSetting(
-    override val key: String,
-    override val category: Settings.Category
-) : AbstractShortSetting {
-    RENDERER_SPEED_LIMIT("speed_limit", Settings.Category.Core);
+enum class ShortSetting(override val key: String) : AbstractShortSetting {
+    RENDERER_SPEED_LIMIT("speed_limit");
 
 
-    override val short: Short
-        get() = NativeConfig.getShort(key, false)
+    override fun getShort(needsGlobal: Boolean): Short = NativeConfig.getShort(key, needsGlobal)
 
 
-    override fun setShort(value: Short) = NativeConfig.setShort(key, value)
+    override fun setShort(value: Short) {
+        if (NativeConfig.isPerGameConfigLoaded()) {
+            global = false
+        }
+        NativeConfig.setShort(key, value)
+    }
 
 
-    override val defaultValue: Short by lazy { NativeConfig.getShort(key, true) }
+    override val defaultValue: Short by lazy { NativeConfig.getDefaultToString(key).toShort() }
 
 
-    override val valueAsString: String
-        get() = short.toString()
+    override fun getValueAsString(needsGlobal: Boolean): String = getShort(needsGlobal).toString()
 
 
     override fun reset() = NativeConfig.setShort(key, defaultValue)
     override fun reset() = NativeConfig.setShort(key, defaultValue)
 }
 }

+ 11 - 12
src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/StringSetting.kt

@@ -5,22 +5,21 @@ package org.yuzu.yuzu_emu.features.settings.model
 
 
 import org.yuzu.yuzu_emu.utils.NativeConfig
 import org.yuzu.yuzu_emu.utils.NativeConfig
 
 
-enum class StringSetting(
-    override val key: String,
-    override val category: Settings.Category
-) : AbstractStringSetting {
-    // No string settings currently exist
-    EMPTY_SETTING("", Settings.Category.UiGeneral);
+enum class StringSetting(override val key: String) : AbstractStringSetting {
+    DRIVER_PATH("driver_path");
 
 
-    override val string: String
-        get() = NativeConfig.getString(key, false)
+    override fun getString(needsGlobal: Boolean): String = NativeConfig.getString(key, needsGlobal)
 
 
-    override fun setString(value: String) = NativeConfig.setString(key, value)
+    override fun setString(value: String) {
+        if (NativeConfig.isPerGameConfigLoaded()) {
+            global = false
+        }
+        NativeConfig.setString(key, value)
+    }
 
 
-    override val defaultValue: String by lazy { NativeConfig.getString(key, true) }
+    override val defaultValue: String by lazy { NativeConfig.getDefaultToString(key) }
 
 
-    override val valueAsString: String
-        get() = string
+    override fun getValueAsString(needsGlobal: Boolean): String = getString(needsGlobal)
 
 
     override fun reset() = NativeConfig.setString(key, defaultValue)
     override fun reset() = NativeConfig.setString(key, defaultValue)
 }
 }

+ 2 - 3
src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/DateTimeSetting.kt

@@ -12,7 +12,6 @@ class DateTimeSetting(
 ) : SettingsItem(longSetting, titleId, descriptionId) {
 ) : SettingsItem(longSetting, titleId, descriptionId) {
     override val type = TYPE_DATETIME_SETTING
     override val type = TYPE_DATETIME_SETTING
 
 
-    var value: Long
-        get() = longSetting.long
-        set(value) = (setting as AbstractLongSetting).setLong(value)
+    fun getValue(needsGlobal: Boolean = false): Long = longSetting.getLong(needsGlobal)
+    fun setValue(value: Long) = (setting as AbstractLongSetting).setLong(value)
 }
 }

+ 18 - 6
src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt

@@ -11,7 +11,6 @@ import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
 import org.yuzu.yuzu_emu.features.settings.model.ByteSetting
 import org.yuzu.yuzu_emu.features.settings.model.ByteSetting
 import org.yuzu.yuzu_emu.features.settings.model.IntSetting
 import org.yuzu.yuzu_emu.features.settings.model.IntSetting
 import org.yuzu.yuzu_emu.features.settings.model.LongSetting
 import org.yuzu.yuzu_emu.features.settings.model.LongSetting
-import org.yuzu.yuzu_emu.features.settings.model.Settings
 import org.yuzu.yuzu_emu.features.settings.model.ShortSetting
 import org.yuzu.yuzu_emu.features.settings.model.ShortSetting
 
 
 /**
 /**
@@ -48,8 +47,8 @@ abstract class SettingsItem(
 
 
         val emptySetting = object : AbstractSetting {
         val emptySetting = object : AbstractSetting {
             override val key: String = ""
             override val key: String = ""
-            override val category: Settings.Category = Settings.Category.Ui
             override val defaultValue: Any = false
             override val defaultValue: Any = false
+            override fun getValueAsString(needsGlobal: Boolean): String = ""
             override fun reset() {}
             override fun reset() {}
         }
         }
 
 
@@ -270,9 +269,9 @@ abstract class SettingsItem(
             )
             )
 
 
             val fastmem = object : AbstractBooleanSetting {
             val fastmem = object : AbstractBooleanSetting {
-                override val boolean: Boolean
-                    get() =
-                        BooleanSetting.FASTMEM.boolean && BooleanSetting.FASTMEM_EXCLUSIVES.boolean
+                override fun getBoolean(needsGlobal: Boolean): Boolean =
+                    BooleanSetting.FASTMEM.getBoolean() &&
+                        BooleanSetting.FASTMEM_EXCLUSIVES.getBoolean()
 
 
                 override fun setBoolean(value: Boolean) {
                 override fun setBoolean(value: Boolean) {
                     BooleanSetting.FASTMEM.setBoolean(value)
                     BooleanSetting.FASTMEM.setBoolean(value)
@@ -280,9 +279,22 @@ abstract class SettingsItem(
                 }
                 }
 
 
                 override val key: String = FASTMEM_COMBINED
                 override val key: String = FASTMEM_COMBINED
-                override val category = Settings.Category.Cpu
                 override val isRuntimeModifiable: Boolean = false
                 override val isRuntimeModifiable: Boolean = false
                 override val defaultValue: Boolean = true
                 override val defaultValue: Boolean = true
+                override val isSwitchable: Boolean = true
+                override var global: Boolean
+                    get() {
+                        return BooleanSetting.FASTMEM.global &&
+                            BooleanSetting.FASTMEM_EXCLUSIVES.global
+                    }
+                    set(value) {
+                        BooleanSetting.FASTMEM.global = value
+                        BooleanSetting.FASTMEM_EXCLUSIVES.global = value
+                    }
+
+                override fun getValueAsString(needsGlobal: Boolean): String =
+                    getBoolean().toString()
+
                 override fun reset() = setBoolean(defaultValue)
                 override fun reset() = setBoolean(defaultValue)
             }
             }
             put(SwitchSetting(fastmem, R.string.fastmem, 0))
             put(SwitchSetting(fastmem, R.string.fastmem, 0))

+ 6 - 11
src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SingleChoiceSetting.kt

@@ -15,16 +15,11 @@ class SingleChoiceSetting(
 ) : SettingsItem(setting, titleId, descriptionId) {
 ) : SettingsItem(setting, titleId, descriptionId) {
     override val type = TYPE_SINGLE_CHOICE
     override val type = TYPE_SINGLE_CHOICE
 
 
-    var selectedValue: Int
-        get() {
-            return when (setting) {
-                is AbstractIntSetting -> setting.int
-                else -> -1
-            }
-        }
-        set(value) {
-            when (setting) {
-                is AbstractIntSetting -> setting.setInt(value)
-            }
+    fun getSelectedValue(needsGlobal: Boolean = false) =
+        when (setting) {
+            is AbstractIntSetting -> setting.getInt(needsGlobal)
+            else -> -1
         }
         }
+
+    fun setSelectedValue(value: Int) = (setting as AbstractIntSetting).setInt(value)
 }
 }

+ 14 - 16
src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SliderSetting.kt

@@ -20,22 +20,20 @@ class SliderSetting(
 ) : SettingsItem(setting, titleId, descriptionId) {
 ) : SettingsItem(setting, titleId, descriptionId) {
     override val type = TYPE_SLIDER
     override val type = TYPE_SLIDER
 
 
-    var selectedValue: Int
-        get() {
-            return when (setting) {
-                is AbstractByteSetting -> setting.byte.toInt()
-                is AbstractShortSetting -> setting.short.toInt()
-                is AbstractIntSetting -> setting.int
-                is AbstractFloatSetting -> setting.float.roundToInt()
-                else -> -1
-            }
+    fun getSelectedValue(needsGlobal: Boolean = false) =
+        when (setting) {
+            is AbstractByteSetting -> setting.getByte(needsGlobal).toInt()
+            is AbstractShortSetting -> setting.getShort(needsGlobal).toInt()
+            is AbstractIntSetting -> setting.getInt(needsGlobal)
+            is AbstractFloatSetting -> setting.getFloat(needsGlobal).roundToInt()
+            else -> -1
         }
         }
-        set(value) {
-            when (setting) {
-                is AbstractByteSetting -> setting.setByte(value.toByte())
-                is AbstractShortSetting -> setting.setShort(value.toShort())
-                is AbstractIntSetting -> setting.setInt(value)
-                is AbstractFloatSetting -> setting.setFloat(value.toFloat())
-            }
+
+    fun setSelectedValue(value: Int) =
+        when (setting) {
+            is AbstractByteSetting -> setting.setByte(value.toByte())
+            is AbstractShortSetting -> setting.setShort(value.toShort())
+            is AbstractFloatSetting -> setting.setFloat(value.toFloat())
+            else -> (setting as AbstractIntSetting).setInt(value)
         }
         }
 }
 }

+ 3 - 4
src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/StringSingleChoiceSetting.kt

@@ -17,14 +17,13 @@ class StringSingleChoiceSetting(
     fun getValueAt(index: Int): String =
     fun getValueAt(index: Int): String =
         if (index >= 0 && index < values.size) values[index] else ""
         if (index >= 0 && index < values.size) values[index] else ""
 
 
-    var selectedValue: String
-        get() = stringSetting.string
-        set(value) = stringSetting.setString(value)
+    fun getSelectedValue(needsGlobal: Boolean = false) = stringSetting.getString(needsGlobal)
+    fun setSelectedValue(value: String) = stringSetting.setString(value)
 
 
     val selectValueIndex: Int
     val selectValueIndex: Int
         get() {
         get() {
             for (i in values.indices) {
             for (i in values.indices) {
-                if (values[i] == selectedValue) {
+                if (values[i] == getSelectedValue()) {
                     return i
                     return i
                 }
                 }
             }
             }

+ 12 - 12
src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SwitchSetting.kt

@@ -14,18 +14,18 @@ class SwitchSetting(
 ) : SettingsItem(setting, titleId, descriptionId) {
 ) : SettingsItem(setting, titleId, descriptionId) {
     override val type = TYPE_SWITCH
     override val type = TYPE_SWITCH
 
 
-    var checked: Boolean
-        get() {
-            return when (setting) {
-                is AbstractIntSetting -> setting.int == 1
-                is AbstractBooleanSetting -> setting.boolean
-                else -> false
-            }
+    fun getIsChecked(needsGlobal: Boolean = false): Boolean {
+        return when (setting) {
+            is AbstractIntSetting -> setting.getInt(needsGlobal) == 1
+            is AbstractBooleanSetting -> setting.getBoolean(needsGlobal)
+            else -> false
         }
         }
-        set(value) {
-            when (setting) {
-                is AbstractIntSetting -> setting.setInt(if (value) 1 else 0)
-                is AbstractBooleanSetting -> setting.setBoolean(value)
-            }
+    }
+
+    fun setChecked(value: Boolean) {
+        when (setting) {
+            is AbstractIntSetting -> setting.setInt(if (value) 1 else 0)
+            is AbstractBooleanSetting -> setting.setBoolean(value)
         }
         }
+    }
 }
 }

+ 6 - 5
src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt

@@ -102,8 +102,9 @@ class SettingsAdapter(
         return currentList[position].type
         return currentList[position].type
     }
     }
 
 
-    fun onBooleanClick(item: SwitchSetting, checked: Boolean) {
-        item.checked = checked
+    fun onBooleanClick(item: SwitchSetting, checked: Boolean, position: Int) {
+        item.setChecked(checked)
+        notifyItemChanged(position)
         settingsViewModel.setShouldReloadSettingsList(true)
         settingsViewModel.setShouldReloadSettingsList(true)
     }
     }
 
 
@@ -126,7 +127,7 @@ class SettingsAdapter(
     }
     }
 
 
     fun onDateTimeClick(item: DateTimeSetting, position: Int) {
     fun onDateTimeClick(item: DateTimeSetting, position: Int) {
-        val storedTime = item.value * 1000
+        val storedTime = item.getValue() * 1000
 
 
         // Helper to extract hour and minute from epoch time
         // Helper to extract hour and minute from epoch time
         val calendar: Calendar = Calendar.getInstance()
         val calendar: Calendar = Calendar.getInstance()
@@ -159,9 +160,9 @@ class SettingsAdapter(
             var epochTime: Long = datePicker.selection!! / 1000
             var epochTime: Long = datePicker.selection!! / 1000
             epochTime += timePicker.hour.toLong() * 60 * 60
             epochTime += timePicker.hour.toLong() * 60 * 60
             epochTime += timePicker.minute.toLong() * 60
             epochTime += timePicker.minute.toLong() * 60
-            if (item.value != epochTime) {
+            if (item.getValue() != epochTime) {
                 notifyItemChanged(position)
                 notifyItemChanged(position)
-                item.value = epochTime
+                item.setValue(epochTime)
             }
             }
         }
         }
         datePicker.show(
         datePicker.show(

+ 19 - 10
src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt

@@ -36,7 +36,14 @@ class SettingsFragmentPresenter(
         val item = SettingsItem.settingsItems[key]!!
         val item = SettingsItem.settingsItems[key]!!
         val pairedSettingKey = item.setting.pairedSettingKey
         val pairedSettingKey = item.setting.pairedSettingKey
         if (pairedSettingKey.isNotEmpty()) {
         if (pairedSettingKey.isNotEmpty()) {
-            val pairedSettingValue = NativeConfig.getBoolean(pairedSettingKey, false)
+            val pairedSettingValue = NativeConfig.getBoolean(
+                pairedSettingKey,
+                if (NativeLibrary.isRunning() && !NativeConfig.isPerGameConfigLoaded()) {
+                    !NativeConfig.usingGlobal(pairedSettingKey)
+                } else {
+                    NativeConfig.usingGlobal(pairedSettingKey)
+                }
+            )
             if (!pairedSettingValue) return
             if (!pairedSettingValue) return
         }
         }
         add(item)
         add(item)
@@ -153,8 +160,8 @@ class SettingsFragmentPresenter(
     private fun addThemeSettings(sl: ArrayList<SettingsItem>) {
     private fun addThemeSettings(sl: ArrayList<SettingsItem>) {
         sl.apply {
         sl.apply {
             val theme: AbstractIntSetting = object : AbstractIntSetting {
             val theme: AbstractIntSetting = object : AbstractIntSetting {
-                override val int: Int
-                    get() = preferences.getInt(Settings.PREF_THEME, 0)
+                override fun getInt(needsGlobal: Boolean): Int =
+                    preferences.getInt(Settings.PREF_THEME, 0)
 
 
                 override fun setInt(value: Int) {
                 override fun setInt(value: Int) {
                     preferences.edit()
                     preferences.edit()
@@ -164,8 +171,8 @@ class SettingsFragmentPresenter(
                 }
                 }
 
 
                 override val key: String = Settings.PREF_THEME
                 override val key: String = Settings.PREF_THEME
-                override val category = Settings.Category.UiGeneral
                 override val isRuntimeModifiable: Boolean = false
                 override val isRuntimeModifiable: Boolean = false
+                override fun getValueAsString(needsGlobal: Boolean): String = getInt().toString()
                 override val defaultValue: Int = 0
                 override val defaultValue: Int = 0
                 override fun reset() {
                 override fun reset() {
                     preferences.edit()
                     preferences.edit()
@@ -197,8 +204,8 @@ class SettingsFragmentPresenter(
             }
             }
 
 
             val themeMode: AbstractIntSetting = object : AbstractIntSetting {
             val themeMode: AbstractIntSetting = object : AbstractIntSetting {
-                override val int: Int
-                    get() = preferences.getInt(Settings.PREF_THEME_MODE, -1)
+                override fun getInt(needsGlobal: Boolean): Int =
+                    preferences.getInt(Settings.PREF_THEME_MODE, -1)
 
 
                 override fun setInt(value: Int) {
                 override fun setInt(value: Int) {
                     preferences.edit()
                     preferences.edit()
@@ -208,8 +215,8 @@ class SettingsFragmentPresenter(
                 }
                 }
 
 
                 override val key: String = Settings.PREF_THEME_MODE
                 override val key: String = Settings.PREF_THEME_MODE
-                override val category = Settings.Category.UiGeneral
                 override val isRuntimeModifiable: Boolean = false
                 override val isRuntimeModifiable: Boolean = false
+                override fun getValueAsString(needsGlobal: Boolean): String = getInt().toString()
                 override val defaultValue: Int = -1
                 override val defaultValue: Int = -1
                 override fun reset() {
                 override fun reset() {
                     preferences.edit()
                     preferences.edit()
@@ -230,8 +237,8 @@ class SettingsFragmentPresenter(
             )
             )
 
 
             val blackBackgrounds: AbstractBooleanSetting = object : AbstractBooleanSetting {
             val blackBackgrounds: AbstractBooleanSetting = object : AbstractBooleanSetting {
-                override val boolean: Boolean
-                    get() = preferences.getBoolean(Settings.PREF_BLACK_BACKGROUNDS, false)
+                override fun getBoolean(needsGlobal: Boolean): Boolean =
+                    preferences.getBoolean(Settings.PREF_BLACK_BACKGROUNDS, false)
 
 
                 override fun setBoolean(value: Boolean) {
                 override fun setBoolean(value: Boolean) {
                     preferences.edit()
                     preferences.edit()
@@ -241,8 +248,10 @@ class SettingsFragmentPresenter(
                 }
                 }
 
 
                 override val key: String = Settings.PREF_BLACK_BACKGROUNDS
                 override val key: String = Settings.PREF_BLACK_BACKGROUNDS
-                override val category = Settings.Category.UiGeneral
                 override val isRuntimeModifiable: Boolean = false
                 override val isRuntimeModifiable: Boolean = false
+                override fun getValueAsString(needsGlobal: Boolean): String =
+                    getBoolean().toString()
+
                 override val defaultValue: Boolean = false
                 override val defaultValue: Boolean = false
                 override fun reset() {
                 override fun reset() {
                     preferences.edit()
                     preferences.edit()

+ 1 - 1
src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt

@@ -29,7 +29,7 @@ class DateTimeViewHolder(val binding: ListItemSettingBinding, adapter: SettingsA
         }
         }
 
 
         binding.textSettingValue.visibility = View.VISIBLE
         binding.textSettingValue.visibility = View.VISIBLE
-        val epochTime = setting.value
+        val epochTime = setting.getValue()
         val instant = Instant.ofEpochMilli(epochTime * 1000)
         val instant = Instant.ofEpochMilli(epochTime * 1000)
         val zonedTime = ZonedDateTime.ofInstant(instant, ZoneId.of("UTC"))
         val zonedTime = ZonedDateTime.ofInstant(instant, ZoneId.of("UTC"))
         val dateFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)
         val dateFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)

+ 2 - 2
src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SingleChoiceViewHolder.kt

@@ -29,14 +29,14 @@ class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: Setti
             val resMgr = binding.textSettingValue.context.resources
             val resMgr = binding.textSettingValue.context.resources
             val values = resMgr.getIntArray(item.valuesId)
             val values = resMgr.getIntArray(item.valuesId)
             for (i in values.indices) {
             for (i in values.indices) {
-                if (values[i] == item.selectedValue) {
+                if (values[i] == item.getSelectedValue()) {
                     binding.textSettingValue.text = resMgr.getStringArray(item.choicesId)[i]
                     binding.textSettingValue.text = resMgr.getStringArray(item.choicesId)[i]
                     break
                     break
                 }
                 }
             }
             }
         } else if (item is StringSingleChoiceSetting) {
         } else if (item is StringSingleChoiceSetting) {
             for (i in item.values.indices) {
             for (i in item.values.indices) {
-                if (item.values[i] == item.selectedValue) {
+                if (item.values[i] == item.getSelectedValue()) {
                     binding.textSettingValue.text = item.choices[i]
                     binding.textSettingValue.text = item.choices[i]
                     break
                     break
                 }
                 }

+ 1 - 1
src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SliderViewHolder.kt

@@ -26,7 +26,7 @@ class SliderViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAda
         binding.textSettingValue.visibility = View.VISIBLE
         binding.textSettingValue.visibility = View.VISIBLE
         binding.textSettingValue.text = String.format(
         binding.textSettingValue.text = String.format(
             binding.textSettingValue.context.getString(R.string.value_with_units),
             binding.textSettingValue.context.getString(R.string.value_with_units),
-            setting.selectedValue,
+            setting.getSelectedValue(),
             setting.units
             setting.units
         )
         )
 
 

+ 1 - 1
src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt

@@ -27,7 +27,7 @@ class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter
         }
         }
 
 
         binding.switchWidget.setOnCheckedChangeListener(null)
         binding.switchWidget.setOnCheckedChangeListener(null)
-        binding.switchWidget.isChecked = setting.checked
+        binding.switchWidget.isChecked = setting.getIsChecked(setting.needsRuntimeGlobal)
         binding.switchWidget.setOnCheckedChangeListener { _: CompoundButton, _: Boolean ->
         binding.switchWidget.setOnCheckedChangeListener { _: CompoundButton, _: Boolean ->
             adapter.onBooleanClick(item, binding.switchWidget.isChecked)
             adapter.onBooleanClick(item, binding.switchWidget.isChecked)
         }
         }

+ 3 - 3
src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt

@@ -435,7 +435,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
     @SuppressLint("SourceLockedOrientationActivity")
     @SuppressLint("SourceLockedOrientationActivity")
     private fun updateOrientation() {
     private fun updateOrientation() {
         emulationActivity?.let {
         emulationActivity?.let {
-            it.requestedOrientation = when (IntSetting.RENDERER_SCREEN_LAYOUT.int) {
+            it.requestedOrientation = when (IntSetting.RENDERER_SCREEN_LAYOUT.getInt()) {
                 Settings.LayoutOption_MobileLandscape ->
                 Settings.LayoutOption_MobileLandscape ->
                     ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
                     ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
                 Settings.LayoutOption_MobilePortrait ->
                 Settings.LayoutOption_MobilePortrait ->
@@ -617,7 +617,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
     @SuppressLint("SourceLockedOrientationActivity")
     @SuppressLint("SourceLockedOrientationActivity")
     private fun startConfiguringControls() {
     private fun startConfiguringControls() {
         // Lock the current orientation to prevent editing inconsistencies
         // Lock the current orientation to prevent editing inconsistencies
-        if (IntSetting.RENDERER_SCREEN_LAYOUT.int == Settings.LayoutOption_Unspecified) {
+        if (IntSetting.RENDERER_SCREEN_LAYOUT.getInt() == Settings.LayoutOption_Unspecified) {
             emulationActivity?.let {
             emulationActivity?.let {
                 it.requestedOrientation =
                 it.requestedOrientation =
                     if (resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT) {
                     if (resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT) {
@@ -635,7 +635,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
         binding.doneControlConfig.visibility = View.GONE
         binding.doneControlConfig.visibility = View.GONE
         binding.surfaceInputOverlay.setIsInEditMode(false)
         binding.surfaceInputOverlay.setIsInEditMode(false)
         // Unlock the orientation if it was locked for editing
         // Unlock the orientation if it was locked for editing
-        if (IntSetting.RENDERER_SCREEN_LAYOUT.int == Settings.LayoutOption_Unspecified) {
+        if (IntSetting.RENDERER_SCREEN_LAYOUT.getInt() == Settings.LayoutOption_Unspecified) {
             emulationActivity?.let {
             emulationActivity?.let {
                 it.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
                 it.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
             }
             }

+ 6 - 6
src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SettingsDialogFragment.kt

@@ -70,7 +70,7 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
                 sliderBinding = DialogSliderBinding.inflate(layoutInflater)
                 sliderBinding = DialogSliderBinding.inflate(layoutInflater)
                 val item = settingsViewModel.clickedItem as SliderSetting
                 val item = settingsViewModel.clickedItem as SliderSetting
 
 
-                settingsViewModel.setSliderTextValue(item.selectedValue.toFloat(), item.units)
+                settingsViewModel.setSliderTextValue(item.getSelectedValue().toFloat(), item.units)
                 sliderBinding.slider.apply {
                 sliderBinding.slider.apply {
                     valueFrom = item.min.toFloat()
                     valueFrom = item.min.toFloat()
                     valueTo = item.max.toFloat()
                     valueTo = item.max.toFloat()
@@ -136,18 +136,18 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
             is SingleChoiceSetting -> {
             is SingleChoiceSetting -> {
                 val scSetting = settingsViewModel.clickedItem as SingleChoiceSetting
                 val scSetting = settingsViewModel.clickedItem as SingleChoiceSetting
                 val value = getValueForSingleChoiceSelection(scSetting, which)
                 val value = getValueForSingleChoiceSelection(scSetting, which)
-                scSetting.selectedValue = value
+                scSetting.setSelectedValue(value)
             }
             }
 
 
             is StringSingleChoiceSetting -> {
             is StringSingleChoiceSetting -> {
                 val scSetting = settingsViewModel.clickedItem as StringSingleChoiceSetting
                 val scSetting = settingsViewModel.clickedItem as StringSingleChoiceSetting
                 val value = scSetting.getValueAt(which)
                 val value = scSetting.getValueAt(which)
-                scSetting.selectedValue = value
+                scSetting.setSelectedValue(value)
             }
             }
 
 
             is SliderSetting -> {
             is SliderSetting -> {
                 val sliderSetting = settingsViewModel.clickedItem as SliderSetting
                 val sliderSetting = settingsViewModel.clickedItem as SliderSetting
-                sliderSetting.selectedValue = settingsViewModel.sliderProgress.value
+                sliderSetting.setSelectedValue(settingsViewModel.sliderProgress.value)
             }
             }
         }
         }
         closeDialog()
         closeDialog()
@@ -171,7 +171,7 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
     }
     }
 
 
     private fun getSelectionForSingleChoiceValue(item: SingleChoiceSetting): Int {
     private fun getSelectionForSingleChoiceValue(item: SingleChoiceSetting): Int {
-        val value = item.selectedValue
+        val value = item.getSelectedValue()
         val valuesId = item.valuesId
         val valuesId = item.valuesId
         if (valuesId > 0) {
         if (valuesId > 0) {
             val valuesArray = requireContext().resources.getIntArray(valuesId)
             val valuesArray = requireContext().resources.getIntArray(valuesId)
@@ -211,7 +211,7 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
                     throw IllegalArgumentException("[SettingsDialogFragment] Incompatible type!")
                     throw IllegalArgumentException("[SettingsDialogFragment] Incompatible type!")
 
 
                 SettingsItem.TYPE_SLIDER -> settingsViewModel.setSliderProgress(
                 SettingsItem.TYPE_SLIDER -> settingsViewModel.setSliderProgress(
-                    (clickedItem as SliderSetting).selectedValue.toFloat()
+                    (clickedItem as SliderSetting).getSelectedValue().toFloat()
                 )
                 )
             }
             }
             settingsViewModel.clickedItem = clickedItem
             settingsViewModel.clickedItem = clickedItem

+ 39 - 8
src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/NativeConfig.kt

@@ -31,32 +31,63 @@ object NativeConfig {
     external fun saveSettings()
     external fun saveSettings()
 
 
     external fun getBoolean(key: String, getDefault: Boolean): Boolean
     external fun getBoolean(key: String, getDefault: Boolean): Boolean
+
+    @Synchronized
+    external fun getBoolean(key: String, needsGlobal: Boolean): Boolean
+
+    @Synchronized
     external fun setBoolean(key: String, value: Boolean)
     external fun setBoolean(key: String, value: Boolean)
 
 
-    external fun getByte(key: String, getDefault: Boolean): Byte
+    @Synchronized
+    external fun getByte(key: String, needsGlobal: Boolean): Byte
+
+    @Synchronized
     external fun setByte(key: String, value: Byte)
     external fun setByte(key: String, value: Byte)
 
 
-    external fun getShort(key: String, getDefault: Boolean): Short
+    @Synchronized
+    external fun getShort(key: String, needsGlobal: Boolean): Short
+
+    @Synchronized
     external fun setShort(key: String, value: Short)
     external fun setShort(key: String, value: Short)
 
 
-    external fun getInt(key: String, getDefault: Boolean): Int
+    @Synchronized
+    external fun getInt(key: String, needsGlobal: Boolean): Int
+
+    @Synchronized
     external fun setInt(key: String, value: Int)
     external fun setInt(key: String, value: Int)
 
 
-    external fun getFloat(key: String, getDefault: Boolean): Float
+    @Synchronized
+    external fun getFloat(key: String, needsGlobal: Boolean): Float
+
+    @Synchronized
     external fun setFloat(key: String, value: Float)
     external fun setFloat(key: String, value: Float)
 
 
-    external fun getLong(key: String, getDefault: Boolean): Long
+    @Synchronized
+    external fun getLong(key: String, needsGlobal: Boolean): Long
+
+    @Synchronized
     external fun setLong(key: String, value: Long)
     external fun setLong(key: String, value: Long)
 
 
-    external fun getString(key: String, getDefault: Boolean): String
+    @Synchronized
+    external fun getString(key: String, needsGlobal: Boolean): String
+
+    @Synchronized
     external fun setString(key: String, value: String)
     external fun setString(key: String, value: String)
 
 
     external fun getIsRuntimeModifiable(key: String): Boolean
     external fun getIsRuntimeModifiable(key: String): Boolean
 
 
-    external fun getConfigHeader(category: Int): String
-
     external fun getPairedSettingKey(key: String): String
     external fun getPairedSettingKey(key: String): String
 
 
+    external fun getIsSwitchable(key: String): Boolean
+
+    @Synchronized
+    external fun usingGlobal(key: String): Boolean
+
+    @Synchronized
+    external fun setGlobal(key: String, global: Boolean)
+
+    external fun getDefaultToString(key: String): String
+
     /**
     /**
      * Gets every [GameDir] in AndroidSettings::values.game_dirs
      * Gets every [GameDir] in AndroidSettings::values.game_dirs
      */
      */

+ 52 - 74
src/android/app/src/main/jni/native_config.cpp

@@ -49,18 +49,12 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_saveSettings(JNIEnv* env, jobjec
 }
 }
 
 
 jboolean Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getBoolean(JNIEnv* env, jobject obj,
 jboolean Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getBoolean(JNIEnv* env, jobject obj,
-                                                               jstring jkey, jboolean getDefault) {
+                                                               jstring jkey, jboolean needGlobal) {
     auto setting = getSetting<bool>(env, jkey);
     auto setting = getSetting<bool>(env, jkey);
     if (setting == nullptr) {
     if (setting == nullptr) {
         return false;
         return false;
     }
     }
-    setting->SetGlobal(true);
-
-    if (static_cast<bool>(getDefault)) {
-        return setting->GetDefault();
-    }
-
-    return setting->GetValue();
+    return setting->GetValue(static_cast<bool>(needGlobal));
 }
 }
 
 
 void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setBoolean(JNIEnv* env, jobject obj, jstring jkey,
 void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setBoolean(JNIEnv* env, jobject obj, jstring jkey,
@@ -69,23 +63,16 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setBoolean(JNIEnv* env, jobject
     if (setting == nullptr) {
     if (setting == nullptr) {
         return;
         return;
     }
     }
-    setting->SetGlobal(true);
     setting->SetValue(static_cast<bool>(value));
     setting->SetValue(static_cast<bool>(value));
 }
 }
 
 
 jbyte Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getByte(JNIEnv* env, jobject obj, jstring jkey,
 jbyte Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getByte(JNIEnv* env, jobject obj, jstring jkey,
-                                                         jboolean getDefault) {
+                                                         jboolean needGlobal) {
     auto setting = getSetting<u8>(env, jkey);
     auto setting = getSetting<u8>(env, jkey);
     if (setting == nullptr) {
     if (setting == nullptr) {
         return -1;
         return -1;
     }
     }
-    setting->SetGlobal(true);
-
-    if (static_cast<bool>(getDefault)) {
-        return setting->GetDefault();
-    }
-
-    return setting->GetValue();
+    return setting->GetValue(static_cast<bool>(needGlobal));
 }
 }
 
 
 void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setByte(JNIEnv* env, jobject obj, jstring jkey,
 void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setByte(JNIEnv* env, jobject obj, jstring jkey,
@@ -94,23 +81,16 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setByte(JNIEnv* env, jobject obj
     if (setting == nullptr) {
     if (setting == nullptr) {
         return;
         return;
     }
     }
-    setting->SetGlobal(true);
     setting->SetValue(value);
     setting->SetValue(value);
 }
 }
 
 
 jshort Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getShort(JNIEnv* env, jobject obj, jstring jkey,
 jshort Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getShort(JNIEnv* env, jobject obj, jstring jkey,
-                                                           jboolean getDefault) {
+                                                           jboolean needGlobal) {
     auto setting = getSetting<u16>(env, jkey);
     auto setting = getSetting<u16>(env, jkey);
     if (setting == nullptr) {
     if (setting == nullptr) {
         return -1;
         return -1;
     }
     }
-    setting->SetGlobal(true);
-
-    if (static_cast<bool>(getDefault)) {
-        return setting->GetDefault();
-    }
-
-    return setting->GetValue();
+    return setting->GetValue(static_cast<bool>(needGlobal));
 }
 }
 
 
 void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setShort(JNIEnv* env, jobject obj, jstring jkey,
 void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setShort(JNIEnv* env, jobject obj, jstring jkey,
@@ -119,23 +99,16 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setShort(JNIEnv* env, jobject ob
     if (setting == nullptr) {
     if (setting == nullptr) {
         return;
         return;
     }
     }
-    setting->SetGlobal(true);
     setting->SetValue(value);
     setting->SetValue(value);
 }
 }
 
 
 jint Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getInt(JNIEnv* env, jobject obj, jstring jkey,
 jint Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getInt(JNIEnv* env, jobject obj, jstring jkey,
-                                                       jboolean getDefault) {
+                                                       jboolean needGlobal) {
     auto setting = getSetting<int>(env, jkey);
     auto setting = getSetting<int>(env, jkey);
     if (setting == nullptr) {
     if (setting == nullptr) {
         return -1;
         return -1;
     }
     }
-    setting->SetGlobal(true);
-
-    if (static_cast<bool>(getDefault)) {
-        return setting->GetDefault();
-    }
-
-    return setting->GetValue();
+    return setting->GetValue(needGlobal);
 }
 }
 
 
 void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setInt(JNIEnv* env, jobject obj, jstring jkey,
 void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setInt(JNIEnv* env, jobject obj, jstring jkey,
@@ -144,23 +117,16 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setInt(JNIEnv* env, jobject obj,
     if (setting == nullptr) {
     if (setting == nullptr) {
         return;
         return;
     }
     }
-    setting->SetGlobal(true);
     setting->SetValue(value);
     setting->SetValue(value);
 }
 }
 
 
 jfloat Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getFloat(JNIEnv* env, jobject obj, jstring jkey,
 jfloat Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getFloat(JNIEnv* env, jobject obj, jstring jkey,
-                                                           jboolean getDefault) {
+                                                           jboolean needGlobal) {
     auto setting = getSetting<float>(env, jkey);
     auto setting = getSetting<float>(env, jkey);
     if (setting == nullptr) {
     if (setting == nullptr) {
         return -1;
         return -1;
     }
     }
-    setting->SetGlobal(true);
-
-    if (static_cast<bool>(getDefault)) {
-        return setting->GetDefault();
-    }
-
-    return setting->GetValue();
+    return setting->GetValue(static_cast<bool>(needGlobal));
 }
 }
 
 
 void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setFloat(JNIEnv* env, jobject obj, jstring jkey,
 void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setFloat(JNIEnv* env, jobject obj, jstring jkey,
@@ -169,23 +135,16 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setFloat(JNIEnv* env, jobject ob
     if (setting == nullptr) {
     if (setting == nullptr) {
         return;
         return;
     }
     }
-    setting->SetGlobal(true);
     setting->SetValue(value);
     setting->SetValue(value);
 }
 }
 
 
 jlong Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getLong(JNIEnv* env, jobject obj, jstring jkey,
 jlong Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getLong(JNIEnv* env, jobject obj, jstring jkey,
-                                                         jboolean getDefault) {
-    auto setting = getSetting<long>(env, jkey);
+                                                         jboolean needGlobal) {
+    auto setting = getSetting<s64>(env, jkey);
     if (setting == nullptr) {
     if (setting == nullptr) {
         return -1;
         return -1;
     }
     }
-    setting->SetGlobal(true);
-
-    if (static_cast<bool>(getDefault)) {
-        return setting->GetDefault();
-    }
-
-    return setting->GetValue();
+    return setting->GetValue(static_cast<bool>(needGlobal));
 }
 }
 
 
 void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setLong(JNIEnv* env, jobject obj, jstring jkey,
 void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setLong(JNIEnv* env, jobject obj, jstring jkey,
@@ -194,23 +153,16 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setLong(JNIEnv* env, jobject obj
     if (setting == nullptr) {
     if (setting == nullptr) {
         return;
         return;
     }
     }
-    setting->SetGlobal(true);
     setting->SetValue(value);
     setting->SetValue(value);
 }
 }
 
 
 jstring Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getString(JNIEnv* env, jobject obj, jstring jkey,
 jstring Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getString(JNIEnv* env, jobject obj, jstring jkey,
-                                                             jboolean getDefault) {
+                                                             jboolean needGlobal) {
     auto setting = getSetting<std::string>(env, jkey);
     auto setting = getSetting<std::string>(env, jkey);
     if (setting == nullptr) {
     if (setting == nullptr) {
         return ToJString(env, "");
         return ToJString(env, "");
     }
     }
-    setting->SetGlobal(true);
-
-    if (static_cast<bool>(getDefault)) {
-        return ToJString(env, setting->GetDefault());
-    }
-
-    return ToJString(env, setting->GetValue());
+    return ToJString(env, setting->GetValue(static_cast<bool>(needGlobal)));
 }
 }
 
 
 void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setString(JNIEnv* env, jobject obj, jstring jkey,
 void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setString(JNIEnv* env, jobject obj, jstring jkey,
@@ -220,27 +172,18 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setString(JNIEnv* env, jobject o
         return;
         return;
     }
     }
 
 
-    setting->SetGlobal(true);
     setting->SetValue(GetJString(env, value));
     setting->SetValue(GetJString(env, value));
 }
 }
 
 
 jboolean Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getIsRuntimeModifiable(JNIEnv* env, jobject obj,
 jboolean Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getIsRuntimeModifiable(JNIEnv* env, jobject obj,
                                                                            jstring jkey) {
                                                                            jstring jkey) {
-    auto key = GetJString(env, jkey);
-    auto setting = Settings::values.linkage.by_key[key];
-    if (setting != 0) {
+    auto setting = getSetting<std::string>(env, jkey);
+    if (setting != nullptr) {
         return setting->RuntimeModfiable();
         return setting->RuntimeModfiable();
     }
     }
-    LOG_ERROR(Frontend, "[Android Native] Could not find setting - {}", key);
     return true;
     return true;
 }
 }
 
 
-jstring Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getConfigHeader(JNIEnv* env, jobject obj,
-                                                                   jint jcategory) {
-    auto category = static_cast<Settings::Category>(jcategory);
-    return ToJString(env, Settings::TranslateCategory(category));
-}
-
 jstring Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getPairedSettingKey(JNIEnv* env, jobject obj,
 jstring Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getPairedSettingKey(JNIEnv* env, jobject obj,
                                                                        jstring jkey) {
                                                                        jstring jkey) {
     auto setting = getSetting<std::string>(env, jkey);
     auto setting = getSetting<std::string>(env, jkey);
@@ -254,6 +197,41 @@ jstring Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getPairedSettingKey(JNIEnv* e
     return ToJString(env, setting->PairedSetting()->GetLabel());
     return ToJString(env, setting->PairedSetting()->GetLabel());
 }
 }
 
 
+jboolean Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getIsSwitchable(JNIEnv* env, jobject obj,
+                                                                    jstring jkey) {
+    auto setting = getSetting<std::string>(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<std::string>(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<std::string>(env, jkey);
+    if (setting != nullptr) {
+        setting->SetGlobal(static_cast<bool>(global));
+    }
+}
+
+jstring Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getDefaultToString(JNIEnv* env, jobject obj,
+                                                                      jstring jkey) {
+    auto setting = getSetting<std::string>(env, jkey);
+    if (setting != nullptr) {
+        return ToJString(env, setting->DefaultToString());
+    }
+    return ToJString(env, "");
+}
+
 jobjectArray Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getGameDirs(JNIEnv* env, jobject obj) {
 jobjectArray Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getGameDirs(JNIEnv* env, jobject obj) {
     jclass gameDirClass = IDCache::GetGameDirClass();
     jclass gameDirClass = IDCache::GetGameDirClass();
     jmethodID gameDirConstructor = IDCache::GetGameDirConstructor();
     jmethodID gameDirConstructor = IDCache::GetGameDirConstructor();

+ 4 - 1
src/common/settings_setting.h

@@ -81,6 +81,9 @@ public:
     [[nodiscard]] virtual const Type& GetValue() const {
     [[nodiscard]] virtual const Type& GetValue() const {
         return value;
         return value;
     }
     }
+    [[nodiscard]] virtual const Type& GetValue(bool need_global) const {
+        return value;
+    }
 
 
     /**
     /**
      * Sets the setting to the given value.
      * Sets the setting to the given value.
@@ -353,7 +356,7 @@ public:
         }
         }
         return custom;
         return custom;
     }
     }
-    [[nodiscard]] const Type& GetValue(bool need_global) const {
+    [[nodiscard]] const Type& GetValue(bool need_global) const override final {
         if (use_global || need_global) {
         if (use_global || need_global) {
             return this->value;
             return this->value;
         }
         }