mirror of
https://github.com/Lime3DS/Lime3DS.git
synced 2026-06-08 09:05:02 -06:00
android: Refactor savestate code and add quicksave/quickload slots
This commit is contained in:
parent
b5868c6110
commit
a7b677f833
@ -525,12 +525,28 @@ object NativeLibrary {
|
|||||||
|
|
||||||
external fun removeAmiibo()
|
external fun removeAmiibo()
|
||||||
|
|
||||||
const val SAVESTATE_SLOT_COUNT = 10
|
const val SAVESTATE_SLOT_COUNT = 11
|
||||||
|
const val QUICKSAVE_SLOT = 0
|
||||||
|
|
||||||
external fun getSavestateInfo(): Array<SaveStateInfo>?
|
external fun getSavestateInfo(): Array<SaveStateInfo>?
|
||||||
|
|
||||||
external fun saveState(slot: Int)
|
external fun saveState(slot: Int)
|
||||||
|
|
||||||
|
|
||||||
|
fun loadStateIfAvailable(slot: Int): Boolean {
|
||||||
|
var available = false
|
||||||
|
getSavestateInfo()?.forEach {
|
||||||
|
if (it.slot == slot){
|
||||||
|
available = true
|
||||||
|
return@forEach
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (available) {
|
||||||
|
loadState(slot)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
external fun loadState(slot: Int)
|
external fun loadState(slot: Int)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -76,7 +76,7 @@ class EmulationActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
binding = ActivityEmulationBinding.inflate(layoutInflater)
|
binding = ActivityEmulationBinding.inflate(layoutInflater)
|
||||||
screenAdjustmentUtil = ScreenAdjustmentUtil(windowManager, settingsViewModel.settings)
|
screenAdjustmentUtil = ScreenAdjustmentUtil(windowManager, settingsViewModel.settings)
|
||||||
hotkeyUtility = HotkeyUtility(screenAdjustmentUtil)
|
hotkeyUtility = HotkeyUtility(screenAdjustmentUtil, this)
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
|
|
||||||
val navHostFragment =
|
val navHostFragment =
|
||||||
|
|||||||
@ -8,5 +8,7 @@ enum class Hotkey(val button: Int) {
|
|||||||
SWAP_SCREEN(10001),
|
SWAP_SCREEN(10001),
|
||||||
CYCLE_LAYOUT(10002),
|
CYCLE_LAYOUT(10002),
|
||||||
CLOSE_GAME(10003),
|
CLOSE_GAME(10003),
|
||||||
PAUSE_OR_RESUME(10004);
|
PAUSE_OR_RESUME(10004),
|
||||||
|
QUICKSAVE(10005),
|
||||||
|
QUICKLOAD(10006);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,11 +4,17 @@
|
|||||||
|
|
||||||
package io.github.lime3ds.android.features.hotkeys
|
package io.github.lime3ds.android.features.hotkeys
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.widget.Toast
|
||||||
|
import io.github.lime3ds.android.NativeLibrary
|
||||||
|
import io.github.lime3ds.android.R
|
||||||
import io.github.lime3ds.android.utils.EmulationLifecycleUtil
|
import io.github.lime3ds.android.utils.EmulationLifecycleUtil
|
||||||
import io.github.lime3ds.android.display.ScreenAdjustmentUtil
|
import io.github.lime3ds.android.display.ScreenAdjustmentUtil
|
||||||
|
|
||||||
class HotkeyUtility(private val screenAdjustmentUtil: ScreenAdjustmentUtil) {
|
class HotkeyUtility(private val screenAdjustmentUtil: ScreenAdjustmentUtil, private val context: Context) {
|
||||||
|
// TODO:
|
||||||
|
// hotkeyLoaded should be a global val tracking that tracks if a hotkey is laoded or not
|
||||||
|
// Move Quickload and Quicksave out of shortcuts related to ScreenAdjustmentUtil
|
||||||
val hotkeyButtons = Hotkey.entries.map { it.button }
|
val hotkeyButtons = Hotkey.entries.map { it.button }
|
||||||
|
|
||||||
fun handleHotkey(bindedButton: Int): Boolean {
|
fun handleHotkey(bindedButton: Int): Boolean {
|
||||||
@ -18,6 +24,23 @@ class HotkeyUtility(private val screenAdjustmentUtil: ScreenAdjustmentUtil) {
|
|||||||
Hotkey.CYCLE_LAYOUT.button -> screenAdjustmentUtil.cycleLayouts()
|
Hotkey.CYCLE_LAYOUT.button -> screenAdjustmentUtil.cycleLayouts()
|
||||||
Hotkey.CLOSE_GAME.button -> EmulationLifecycleUtil.closeGame()
|
Hotkey.CLOSE_GAME.button -> EmulationLifecycleUtil.closeGame()
|
||||||
Hotkey.PAUSE_OR_RESUME.button -> EmulationLifecycleUtil.pauseOrResume()
|
Hotkey.PAUSE_OR_RESUME.button -> EmulationLifecycleUtil.pauseOrResume()
|
||||||
|
Hotkey.QUICKSAVE.button -> {
|
||||||
|
NativeLibrary.saveState(NativeLibrary.QUICKSAVE_SLOT)
|
||||||
|
Toast.makeText(context,
|
||||||
|
context.getString(R.string.quicksave_saving),
|
||||||
|
Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
Hotkey.QUICKLOAD.button -> {
|
||||||
|
val hotkeyLoaded = NativeLibrary.loadStateIfAvailable(NativeLibrary.QUICKSAVE_SLOT)
|
||||||
|
val stringRes = if(hotkeyLoaded) {
|
||||||
|
R.string.quickload_loading
|
||||||
|
} else {
|
||||||
|
R.string.quickload_not_found
|
||||||
|
}
|
||||||
|
Toast.makeText(context,
|
||||||
|
context.getString(stringRes),
|
||||||
|
Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
else -> {}
|
else -> {}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|||||||
@ -137,6 +137,8 @@ class Settings {
|
|||||||
const val HOTKEY_CYCLE_LAYOUT = "hotkey_toggle_layout"
|
const val HOTKEY_CYCLE_LAYOUT = "hotkey_toggle_layout"
|
||||||
const val HOTKEY_CLOSE_GAME = "hotkey_close_game"
|
const val HOTKEY_CLOSE_GAME = "hotkey_close_game"
|
||||||
const val HOTKEY_PAUSE_OR_RESUME = "hotkey_pause_or_resume_game"
|
const val HOTKEY_PAUSE_OR_RESUME = "hotkey_pause_or_resume_game"
|
||||||
|
const val HOTKEY_QUICKSAVE = "hotkey_quickload"
|
||||||
|
const val HOTKEY_QUICKlOAD = "hotkey_quickpause"
|
||||||
|
|
||||||
val buttonKeys = listOf(
|
val buttonKeys = listOf(
|
||||||
KEY_BUTTON_A,
|
KEY_BUTTON_A,
|
||||||
@ -200,13 +202,17 @@ class Settings {
|
|||||||
HOTKEY_SCREEN_SWAP,
|
HOTKEY_SCREEN_SWAP,
|
||||||
HOTKEY_CYCLE_LAYOUT,
|
HOTKEY_CYCLE_LAYOUT,
|
||||||
HOTKEY_CLOSE_GAME,
|
HOTKEY_CLOSE_GAME,
|
||||||
HOTKEY_PAUSE_OR_RESUME
|
HOTKEY_PAUSE_OR_RESUME,
|
||||||
|
HOTKEY_QUICKSAVE,
|
||||||
|
HOTKEY_QUICKlOAD
|
||||||
)
|
)
|
||||||
val hotkeyTitles = listOf(
|
val hotkeyTitles = listOf(
|
||||||
R.string.emulation_swap_screens,
|
R.string.emulation_swap_screens,
|
||||||
R.string.emulation_cycle_landscape_layouts,
|
R.string.emulation_cycle_landscape_layouts,
|
||||||
R.string.emulation_close_game,
|
R.string.emulation_close_game,
|
||||||
R.string.emulation_toggle_pause
|
R.string.emulation_toggle_pause,
|
||||||
|
R.string.emulation_quicksave,
|
||||||
|
R.string.emulation_quickload,
|
||||||
)
|
)
|
||||||
|
|
||||||
const val PREF_FIRST_APP_LAUNCH = "FirstApplicationLaunch"
|
const val PREF_FIRST_APP_LAUNCH = "FirstApplicationLaunch"
|
||||||
|
|||||||
@ -133,6 +133,8 @@ class InputBindingSetting(
|
|||||||
Settings.HOTKEY_CYCLE_LAYOUT -> Hotkey.CYCLE_LAYOUT.button
|
Settings.HOTKEY_CYCLE_LAYOUT -> Hotkey.CYCLE_LAYOUT.button
|
||||||
Settings.HOTKEY_CLOSE_GAME -> Hotkey.CLOSE_GAME.button
|
Settings.HOTKEY_CLOSE_GAME -> Hotkey.CLOSE_GAME.button
|
||||||
Settings.HOTKEY_PAUSE_OR_RESUME -> Hotkey.PAUSE_OR_RESUME.button
|
Settings.HOTKEY_PAUSE_OR_RESUME -> Hotkey.PAUSE_OR_RESUME.button
|
||||||
|
Settings.HOTKEY_QUICKSAVE -> Hotkey.QUICKSAVE.button
|
||||||
|
Settings.HOTKEY_QUICKlOAD -> Hotkey.QUICKLOAD.button
|
||||||
else -> -1
|
else -> -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -504,12 +504,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
|
|||||||
popupMenu.setOnMenuItemClickListener {
|
popupMenu.setOnMenuItemClickListener {
|
||||||
when (it.itemId) {
|
when (it.itemId) {
|
||||||
R.id.menu_emulation_save_state -> {
|
R.id.menu_emulation_save_state -> {
|
||||||
showSaveStateSubmenu()
|
showStateSubmenu(true)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.menu_emulation_load_state -> {
|
R.id.menu_emulation_load_state -> {
|
||||||
showLoadStateSubmenu()
|
showStateSubmenu(false)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -520,7 +520,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
|
|||||||
popupMenu.show()
|
popupMenu.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showSaveStateSubmenu() {
|
private fun showStateSubmenu(isSaving: Boolean) {
|
||||||
|
|
||||||
val savestates = NativeLibrary.getSavestateInfo()
|
val savestates = NativeLibrary.getSavestateInfo()
|
||||||
|
|
||||||
val popupMenu = PopupMenu(
|
val popupMenu = PopupMenu(
|
||||||
@ -530,46 +531,40 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
|
|||||||
|
|
||||||
popupMenu.menu.apply {
|
popupMenu.menu.apply {
|
||||||
for (i in 0 until NativeLibrary.SAVESTATE_SLOT_COUNT) {
|
for (i in 0 until NativeLibrary.SAVESTATE_SLOT_COUNT) {
|
||||||
val slot = i + 1
|
val slot = i
|
||||||
val text = getString(R.string.emulation_empty_state_slot, slot)
|
var enableClick = isSaving
|
||||||
add(text).setEnabled(true).setOnMenuItemClickListener {
|
val text = if (slot == NativeLibrary.QUICKSAVE_SLOT) {
|
||||||
displaySavestateWarning()
|
enableClick = false
|
||||||
NativeLibrary.saveState(slot)
|
getString(R.string.emulation_quicksave_slot)
|
||||||
|
} else {
|
||||||
|
getString(R.string.emulation_empty_state_slot, slot)
|
||||||
|
}
|
||||||
|
|
||||||
|
add(text).setEnabled(enableClick).setOnMenuItemClickListener {
|
||||||
|
if(isSaving) {
|
||||||
|
NativeLibrary.saveState(slot)
|
||||||
|
} else {
|
||||||
|
NativeLibrary.loadState(slot)
|
||||||
|
binding.drawerLayout.close()
|
||||||
|
Toast.makeText(context,
|
||||||
|
getString(R.string.quickload_loading),
|
||||||
|
Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
savestates?.forEach {
|
savestates?.forEach {
|
||||||
val text = getString(R.string.emulation_occupied_state_slot, it.slot, it.time)
|
var enableClick = true
|
||||||
popupMenu.menu.getItem(it.slot - 1).setTitle(text)
|
val text = if(it.slot == NativeLibrary.QUICKSAVE_SLOT) {
|
||||||
}
|
// do not allow saving in quicksave slot
|
||||||
|
enableClick = !isSaving
|
||||||
popupMenu.show()
|
getString(R.string.emulation_occupied_quicksave_slot, it.time)
|
||||||
}
|
} else{
|
||||||
|
getString(R.string.emulation_occupied_state_slot, it.slot, it.time)
|
||||||
private fun showLoadStateSubmenu() {
|
|
||||||
val savestates = NativeLibrary.getSavestateInfo()
|
|
||||||
|
|
||||||
val popupMenu = PopupMenu(
|
|
||||||
requireContext(),
|
|
||||||
binding.inGameMenu.findViewById(R.id.menu_emulation_savestates)
|
|
||||||
)
|
|
||||||
|
|
||||||
popupMenu.menu.apply {
|
|
||||||
for (i in 0 until NativeLibrary.SAVESTATE_SLOT_COUNT) {
|
|
||||||
val slot = i + 1
|
|
||||||
val text = getString(R.string.emulation_empty_state_slot, slot)
|
|
||||||
add(text).setEnabled(false).setOnMenuItemClickListener {
|
|
||||||
NativeLibrary.loadState(slot)
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
popupMenu.menu.getItem(it.slot).setTitle(text).setEnabled(enableClick)
|
||||||
|
|
||||||
savestates?.forEach {
|
|
||||||
val text = getString(R.string.emulation_occupied_state_slot, it.slot, it.time)
|
|
||||||
popupMenu.menu.getItem(it.slot - 1).setTitle(text).setEnabled(true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
popupMenu.show()
|
popupMenu.show()
|
||||||
|
|||||||
@ -140,6 +140,16 @@
|
|||||||
<string name="input_message_analog_only">This control must be bound to a gamepad analog stick or D-pad axis!</string>
|
<string name="input_message_analog_only">This control must be bound to a gamepad analog stick or D-pad axis!</string>
|
||||||
<string name="input_message_button_only">This control must be bound to a gamepad button!</string>
|
<string name="input_message_button_only">This control must be bound to a gamepad button!</string>
|
||||||
|
|
||||||
|
<!-- Quickload&Save-->
|
||||||
|
<string name="emulation_quicksave_slot">Quicksave</string>
|
||||||
|
<string name="emulation_quicksave">Quicksave</string>
|
||||||
|
<string name="emulation_quickload">Quickload</string>
|
||||||
|
<string name="emulation_occupied_quicksave_slot">Quicksave - %1$tF %1$tR</string>
|
||||||
|
<string name="quicksave_saving">Saving…</string>
|
||||||
|
<string name="quickload_loading">Loading…</string>
|
||||||
|
<string name="quickload_not_found">No Quicksave available.</string>
|
||||||
|
|
||||||
|
|
||||||
<!-- System files strings -->
|
<!-- System files strings -->
|
||||||
<string name="system_files">System Files</string>
|
<string name="system_files">System Files</string>
|
||||||
<string name="system_files_description">Download system files to get Mii files, boot the HOME menu, and more</string>
|
<string name="system_files_description">Download system files to get Mii files, boot the HOME menu, and more</string>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user