From 191c456cc7d576d2831e0dcb8a78be9edfa0b712 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20N=C3=BCsse?= Date: Sat, 9 Aug 2025 11:38:01 +0200 Subject: [PATCH 1/2] Allow the user to quickly load a savestate on game startup --- .../activities/EmulationActivity.kt | 24 +++++++++++++++++++ .../features/settings/model/BooleanSetting.kt | 6 +++++ .../settings/ui/SettingsFragmentPresenter.kt | 8 +++++++ .../dolphinemu/fragments/EmulationFragment.kt | 4 ++++ .../app/src/main/res/values/strings.xml | 3 +++ 5 files changed, 45 insertions(+) diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.kt index b743328920..40f11b8f0f 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.kt @@ -60,6 +60,7 @@ import org.dolphinemu.dolphinemu.ui.main.ThemeProvider import org.dolphinemu.dolphinemu.utils.AfterDirectoryInitializationRunner import org.dolphinemu.dolphinemu.utils.DirectoryInitialization import org.dolphinemu.dolphinemu.utils.FileBrowserHelper +import org.dolphinemu.dolphinemu.utils.Log import org.dolphinemu.dolphinemu.utils.ThemeHelper import kotlin.math.roundToInt @@ -456,6 +457,7 @@ class EmulationActivity : AppCompatActivity(), ThemeProvider { MENU_ACTION_PAUSE_EMULATION -> { hasUserPausedEmulation = true NativeLibrary.PauseEmulation(false) + saveOnExit() } MENU_ACTION_UNPAUSE_EMULATION -> { @@ -1167,4 +1169,26 @@ class EmulationActivity : AppCompatActivity(), ThemeProvider { return !viewBounds.contains(x.roundToInt(), y.roundToInt()) } } + + fun saveOnExit() { + if (BooleanSetting.MAIN_EXIT_SAVE_AND_LOAD.boolean) { + Log.error("[EmulationActivity] Exitsave on Pause") + NativeLibrary.SaveState(10, true) + } + } + + fun loadExitsaveOnStart() { + if (BooleanSetting.MAIN_EXIT_SAVE_AND_LOAD.boolean) { + while (!NativeLibrary.IsRunningAndUnpaused()){ + Thread.sleep(10) + } + Log.error("[EmulationActivity] Load Exitsave on start") + val creationTime = NativeLibrary.GetUnixTimeOfStateSlot(9) + if (creationTime != 0L) { + NativeLibrary.LoadState(9) + } else { + Log.error("[EmulationActivity] Exitsave-Slot not available") + } + } + } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/BooleanSetting.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/BooleanSetting.kt index 0b6945ff13..1c06929a89 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/BooleanSetting.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/BooleanSetting.kt @@ -136,6 +136,12 @@ enum class BooleanSetting( "EnableSaveStates", false ), + MAIN_EXIT_SAVE_AND_LOAD( + Settings.FILE_DOLPHIN, + Settings.SECTION_INI_CORE, + "EnableExitSaveAndLoad", + false + ), MAIN_WII_WIILINK_ENABLE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "EnableWiiLink", false), MAIN_DSP_JIT(Settings.FILE_DOLPHIN, Settings.SECTION_INI_DSP, "EnableJIT", true), MAIN_TIME_TRACKING( diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.kt index 25acccb2fc..38a188db81 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.kt @@ -291,6 +291,14 @@ class SettingsFragmentPresenter( R.string.enable_save_states_description ) ) + sl.add( + SwitchSetting( + context, + BooleanSetting.MAIN_EXIT_SAVE_AND_LOAD, + R.string.enable_exit_save_and_load, + R.string.enable_exit_save_and_load_description + ) + ) } private fun addInterfaceSettings(sl: ArrayList) { diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.kt index 04db24c03a..94c4b5af27 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.kt @@ -111,6 +111,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { Log.debug("[EmulationFragment] Pausing emulation.") NativeLibrary.PauseEmulation(true) } + // create exitsave here too, in case android kills the paused process + emulationActivity?.saveOnExit() super.onPause() } @@ -161,6 +163,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { } fun stopEmulation() { + emulationActivity?.saveOnExit() Log.debug("[EmulationFragment] Stopping emulation.") NativeLibrary.StopEmulation() } @@ -220,6 +223,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { EmulationActivity.stopIgnoringLaunchRequests() }, "NativeEmulation") emulationThread.start() + emulationActivity?.loadExitsaveOnStart() } else { if (!EmulationActivity.hasUserPausedEmulation && !NativeLibrary.IsShowingAlertMessage()) { Log.debug("[EmulationFragment] Resuming emulation.") diff --git a/Source/Android/app/src/main/res/values/strings.xml b/Source/Android/app/src/main/res/values/strings.xml index 51406cd7e3..6005092e23 100644 --- a/Source/Android/app/src/main/res/values/strings.xml +++ b/Source/Android/app/src/main/res/values/strings.xml @@ -32,6 +32,7 @@ Extension Device + TEST Create Mappings for Other Devices Detects inputs from all devices, not just the selected device. Profile @@ -126,6 +127,8 @@ Fallback Region Enable Savestates WARNING: Savestates may not be compatible with future versions of Dolphin and can make it impossible to create normal saves in some cases. Never use savestates as the only way of saving your progress. + Enable Exitsave and Quickload + Pick it right up where you left it! This will save your game every time you exit the game, and loads it back when you start it again. Enable usage statistics reporting If authorized, Dolphin can collect data on its performance, feature usage, and configuration, as well as data on your system\'s hardware and operating system.\n\nNo private data is ever collected. This data helps us understand how people and emulated games use Dolphin and prioritize our efforts. It also helps us identify rare configurations that are causing bugs, performance and stability issues. This authorization can be revoked at any time through Dolphin\'s settings. Generate a New Statistics Identity From 891587ee3c95380611a2f2d908068ecf3de883d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20N=C3=BCsse?= Date: Sat, 9 Aug 2025 16:22:19 +0200 Subject: [PATCH 2/2] add Saveslot enum --- .../activities/EmulationActivity.kt | 36 +++++++++---------- .../dolphinemu/dolphinemu/model/SAVESLOT.kt | 12 +++++++ 2 files changed, 30 insertions(+), 18 deletions(-) create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/SAVESLOT.kt diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.kt index 40f11b8f0f..47d92815bf 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.kt @@ -2,7 +2,6 @@ package org.dolphinemu.dolphinemu.activities -import android.annotation.SuppressLint import android.content.DialogInterface import android.content.Intent import android.graphics.Rect @@ -53,6 +52,7 @@ import org.dolphinemu.dolphinemu.fragments.EmulationFragment import org.dolphinemu.dolphinemu.fragments.MenuFragment import org.dolphinemu.dolphinemu.fragments.SaveLoadStateFragment import org.dolphinemu.dolphinemu.fragments.SaveLoadStateFragment.SaveOrLoad +import org.dolphinemu.dolphinemu.model.SAVESLOT.* import org.dolphinemu.dolphinemu.overlay.InputOverlay import org.dolphinemu.dolphinemu.overlay.InputOverlayPointer import org.dolphinemu.dolphinemu.ui.main.MainPresenter @@ -466,22 +466,22 @@ class EmulationActivity : AppCompatActivity(), ThemeProvider { } MENU_ACTION_TAKE_SCREENSHOT -> NativeLibrary.SaveScreenShot() - MENU_ACTION_QUICK_SAVE -> NativeLibrary.SaveState(9, false) - MENU_ACTION_QUICK_LOAD -> NativeLibrary.LoadState(9) + MENU_ACTION_QUICK_SAVE -> NativeLibrary.SaveState(QUICKSAVE.slot, false) + MENU_ACTION_QUICK_LOAD -> NativeLibrary.LoadState(QUICKSAVE.slot) MENU_ACTION_SAVE_ROOT -> showSubMenu(SaveOrLoad.SAVE) MENU_ACTION_LOAD_ROOT -> showSubMenu(SaveOrLoad.LOAD) - MENU_ACTION_SAVE_SLOT1 -> NativeLibrary.SaveState(0, false) - MENU_ACTION_SAVE_SLOT2 -> NativeLibrary.SaveState(1, false) - MENU_ACTION_SAVE_SLOT3 -> NativeLibrary.SaveState(2, false) - MENU_ACTION_SAVE_SLOT4 -> NativeLibrary.SaveState(3, false) - MENU_ACTION_SAVE_SLOT5 -> NativeLibrary.SaveState(4, false) - MENU_ACTION_SAVE_SLOT6 -> NativeLibrary.SaveState(5, false) - MENU_ACTION_LOAD_SLOT1 -> NativeLibrary.LoadState(0) - MENU_ACTION_LOAD_SLOT2 -> NativeLibrary.LoadState(1) - MENU_ACTION_LOAD_SLOT3 -> NativeLibrary.LoadState(2) - MENU_ACTION_LOAD_SLOT4 -> NativeLibrary.LoadState(3) - MENU_ACTION_LOAD_SLOT5 -> NativeLibrary.LoadState(4) - MENU_ACTION_LOAD_SLOT6 -> NativeLibrary.LoadState(5) + MENU_ACTION_SAVE_SLOT1 -> NativeLibrary.SaveState(SLOT1.slot, false) + MENU_ACTION_SAVE_SLOT2 -> NativeLibrary.SaveState(SLOT2.slot, false) + MENU_ACTION_SAVE_SLOT3 -> NativeLibrary.SaveState(SLOT3.slot, false) + MENU_ACTION_SAVE_SLOT4 -> NativeLibrary.SaveState(SLOT4.slot, false) + MENU_ACTION_SAVE_SLOT5 -> NativeLibrary.SaveState(SLOT5.slot, false) + MENU_ACTION_SAVE_SLOT6 -> NativeLibrary.SaveState(SLOT6.slot, false) + MENU_ACTION_LOAD_SLOT1 -> NativeLibrary.LoadState(SLOT1.slot) + MENU_ACTION_LOAD_SLOT2 -> NativeLibrary.LoadState(SLOT2.slot) + MENU_ACTION_LOAD_SLOT3 -> NativeLibrary.LoadState(SLOT3.slot) + MENU_ACTION_LOAD_SLOT4 -> NativeLibrary.LoadState(SLOT4.slot) + MENU_ACTION_LOAD_SLOT5 -> NativeLibrary.LoadState(SLOT5.slot) + MENU_ACTION_LOAD_SLOT6 -> NativeLibrary.LoadState(SLOT6.slot) MENU_ACTION_CHANGE_DISC -> { val intent = Intent(Intent.ACTION_OPEN_DOCUMENT) intent.addCategory(Intent.CATEGORY_OPENABLE) @@ -1173,7 +1173,7 @@ class EmulationActivity : AppCompatActivity(), ThemeProvider { fun saveOnExit() { if (BooleanSetting.MAIN_EXIT_SAVE_AND_LOAD.boolean) { Log.error("[EmulationActivity] Exitsave on Pause") - NativeLibrary.SaveState(10, true) + NativeLibrary.SaveState(EXITSAVE.slot, true) } } @@ -1183,9 +1183,9 @@ class EmulationActivity : AppCompatActivity(), ThemeProvider { Thread.sleep(10) } Log.error("[EmulationActivity] Load Exitsave on start") - val creationTime = NativeLibrary.GetUnixTimeOfStateSlot(9) + val creationTime = NativeLibrary.GetUnixTimeOfStateSlot(EXITSAVE.slot) if (creationTime != 0L) { - NativeLibrary.LoadState(9) + NativeLibrary.LoadState(EXITSAVE.slot) } else { Log.error("[EmulationActivity] Exitsave-Slot not available") } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/SAVESLOT.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/SAVESLOT.kt new file mode 100644 index 0000000000..988a0906e4 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/SAVESLOT.kt @@ -0,0 +1,12 @@ +package org.dolphinemu.dolphinemu.model + +enum class SAVESLOT(val slot: Int) { + SLOT1(0), + SLOT2(1), + SLOT3(2), + SLOT4(3), + SLOT5(4), + SLOT6(5), + QUICKSAVE(9), + EXITSAVE(10) +} \ No newline at end of file