mirror of
https://github.com/ARMSX2/ARMSX2.git
synced 2026-08-24 16:50:16 -07:00
Android: add a PINE toggle to Advanced settings
EnablePINE and PINESlot were already INI-backed and VMManager::ReloadPINE already starts and stops the server when they change, but the Android frontend never surfaced them, so there was no way to switch PINE on from the device. It sits beside the recompiler switches because it is the same class of control: a developer tool a player has no reason to find, next to the other things you turn on to diagnose rather than to play. The row states the address and, once enabled, the adb forward line -- the listener is on loopback, so it does nothing until a workstation bridges the port, and a port nobody tells you about cannot be bridged. The port itself gets no editing widget. The only reason to move it is running two emulators on one machine, which does not happen on a handheld, and a free-entry port field is a support burden for a knob nobody turns; it stays readable from the INI. It is still carried in the settings model so the row can state the real port rather than assume the default. Note the per-game merge is a full constructor, so a field omitted there resets to its default instead of inheriting: PINE is a process-wide server and cannot be per-game, so it is absent from the diff (no game file ever acquires the key) but explicitly carried through the merge.
This commit is contained in:
@@ -177,6 +177,18 @@ data class Settings(
|
||||
/** EmuCore/HostFs — host: filesystem access in the VM, for ELF/homebrew and mods
|
||||
* (e.g. modded Persona 3 FES). Per-game capable; applies on the next game boot. */
|
||||
val hostFs: Boolean = false,
|
||||
/** EmuCore/EnablePINE — the IPC server external tools drive the emulator through
|
||||
* (read/write guest memory, savestates, GS dumps). On Android it listens on loopback
|
||||
* TCP, so it is reachable from a workstation only after `adb forward`; nothing outside
|
||||
* the device can see it. Off by default: it is a debugging tool, and a listening socket
|
||||
* a player did not ask for should not exist. */
|
||||
val pineEnabled: Boolean = false,
|
||||
/** EmuCore/PINESlot — the port [pineEnabled] listens on. Deliberately has no UI row: the
|
||||
* only reason to move it is running two emulators at once, which does not happen on a
|
||||
* handheld, and a free-entry port field is a support burden for a knob nobody turns.
|
||||
* Kept in the model anyway so the toggle's description can state the real port rather
|
||||
* than assuming the default. Editable in the INI for the rare case that needs it. */
|
||||
val pineSlot: Int = 28011,
|
||||
/** EmuCore/EnableGameFixes — master switch that lets the GameDB apply each game's
|
||||
* curated compatibility gamefixes (e.g. VuAddSubHack, SkipMPEGHack). Defaults TRUE
|
||||
* to match upstream PCSX2 (Pcsx2Config.cpp EnableGameFixes = true) and trak's Mac:
|
||||
@@ -799,6 +811,10 @@ data class Settings(
|
||||
put("EmuCore", "EnableNoInterlacingPatches", "bool", enableNoInterlacingPatches.toString())
|
||||
put("EmuCore", "EnableFastBoot", "bool", enableFastBoot.toString())
|
||||
put("EmuCore", "HostFs", "bool", hostFs.toString())
|
||||
// VMManager::ReloadPINE compares these against the live server and starts, stops or
|
||||
// rebinds it, so a commit is enough — no game restart.
|
||||
put("EmuCore", "EnablePINE", "bool", pineEnabled.toString())
|
||||
put("EmuCore", "PINESlot", "int", pineSlot.toString())
|
||||
put("EmuCore", "EnableGameFixes", "bool", enableGameFixes.toString())
|
||||
put("EmuCore/Gamefixes", "SoftwareRendererFMVHack", "bool", gamefixSoftwareRendererFmv.toString())
|
||||
put("EmuCore/Gamefixes", "SkipMPEGHack", "bool", gamefixSkipMpeg.toString())
|
||||
@@ -1014,6 +1030,8 @@ data class Settings(
|
||||
enableNoInterlacingPatches = boolAt("EmuCore/EnableNoInterlacingPatches") ?: this.enableNoInterlacingPatches,
|
||||
enableFastBoot = boolAt("EmuCore/EnableFastBoot") ?: this.enableFastBoot,
|
||||
hostFs = boolAt("EmuCore/HostFs") ?: this.hostFs,
|
||||
pineEnabled = boolAt("EmuCore/EnablePINE") ?: this.pineEnabled,
|
||||
pineSlot = intAt("EmuCore/PINESlot") ?: this.pineSlot,
|
||||
enableGameFixes = boolAt("EmuCore/EnableGameFixes") ?: this.enableGameFixes,
|
||||
// ---- EmuCore/Gamefixes ----
|
||||
gamefixSoftwareRendererFmv = boolAt("EmuCore/Gamefixes/SoftwareRendererFMVHack") ?: this.gamefixSoftwareRendererFmv,
|
||||
@@ -1605,6 +1623,8 @@ data class Settings(
|
||||
put("enableNoInterlacingPatches", enableNoInterlacingPatches)
|
||||
put("enableFastBoot", enableFastBoot)
|
||||
put("hostFs", hostFs)
|
||||
put("pineEnabled", pineEnabled)
|
||||
put("pineSlot", pineSlot)
|
||||
put("enableGameFixes", enableGameFixes)
|
||||
put("gamefixSoftwareRendererFmv", gamefixSoftwareRendererFmv)
|
||||
put("gamefixSkipMpeg", gamefixSkipMpeg)
|
||||
@@ -1866,6 +1886,8 @@ data class Settings(
|
||||
enableNoInterlacingPatches = json.optBoolean("enableNoInterlacingPatches", def.enableNoInterlacingPatches),
|
||||
enableFastBoot = json.optBoolean("enableFastBoot", def.enableFastBoot),
|
||||
hostFs = json.optBoolean("hostFs", def.hostFs),
|
||||
pineEnabled = json.optBoolean("pineEnabled", def.pineEnabled),
|
||||
pineSlot = json.optInt("pineSlot", def.pineSlot),
|
||||
enableGameFixes = json.optBoolean("enableGameFixes", def.enableGameFixes),
|
||||
gamefixSoftwareRendererFmv = json.optBoolean("gamefixSoftwareRendererFmv", def.gamefixSoftwareRendererFmv),
|
||||
gamefixSkipMpeg = json.optBoolean("gamefixSkipMpeg", def.gamefixSkipMpeg),
|
||||
@@ -2341,6 +2363,13 @@ data class Settings(
|
||||
enableNoInterlacingPatches = if (overrides.has("enableNoInterlacingPatches")) overrides.getBoolean("enableNoInterlacingPatches") else base.enableNoInterlacingPatches,
|
||||
enableFastBoot = if (overrides.has("enableFastBoot")) overrides.getBoolean("enableFastBoot") else base.enableFastBoot,
|
||||
hostFs = if (overrides.has("hostFs")) overrides.getBoolean("hostFs") else base.hostFs,
|
||||
// Always the global value: PINE is one server for the process, so "this game runs
|
||||
// with PINE on" is not a thing that can be true. Deliberately absent from the diff
|
||||
// above too, so a per-game file never acquires the key -- but it still has to be
|
||||
// listed HERE, because this is a full constructor and an omitted field silently
|
||||
// resets to the default rather than inheriting from base.
|
||||
pineEnabled = base.pineEnabled,
|
||||
pineSlot = base.pineSlot,
|
||||
enableGameFixes = if (overrides.has("enableGameFixes")) overrides.getBoolean("enableGameFixes") else base.enableGameFixes,
|
||||
gamefixSoftwareRendererFmv = if (overrides.has("gamefixSoftwareRendererFmv")) overrides.getBoolean("gamefixSoftwareRendererFmv") else base.gamefixSoftwareRendererFmv,
|
||||
gamefixSkipMpeg = if (overrides.has("gamefixSkipMpeg")) overrides.getBoolean("gamefixSkipMpeg") else base.gamefixSkipMpeg,
|
||||
|
||||
@@ -579,8 +579,12 @@ val EN: Map<String, String> = mapOf(
|
||||
"fixes.screenOffsets.label" to "Screen Offsets",
|
||||
"fixes.section.display" to "Display Fixes",
|
||||
"fixes.section.display.help" to "PCRTC / presentation fixes for the displayed image. Anti-Blur is on by ",
|
||||
"fixes.pine.enable" to "Enable PINE",
|
||||
"fixes.pine.enable.desc" to "Lets an external tool drive the emulator over a local port — read and write guest memory, take savestates, capture GS dumps.",
|
||||
"fixes.section.hardware" to "Hardware Fixes",
|
||||
"fixes.section.hardware.help" to "Manual renderer hacks. The master toggle auto-enables when any fix is ",
|
||||
"fixes.section.pine" to "PINE (Remote Control)",
|
||||
"fixes.section.pine.help" to "The IPC server developer tools connect to. It listens on this device only, so a PC has to bridge the port first — run the command shown below from a machine with the device attached.",
|
||||
"fixes.section.software" to "Software Renderer",
|
||||
"fixes.section.software.help" to "Apply when the Software renderer is selected.",
|
||||
"fixes.section.upscaling" to "Upscaling Fixes",
|
||||
|
||||
@@ -488,10 +488,36 @@ fun FixesTab(state: MutableState<Settings>) {
|
||||
}
|
||||
SettingsDivider()
|
||||
RecompilerSection(state)
|
||||
SettingsDivider()
|
||||
PineSection(state)
|
||||
Spacer(Modifier.height(8.dp))
|
||||
}
|
||||
}
|
||||
|
||||
/** PINE, the IPC server external tools drive the emulator through. Lives beside the recompiler
|
||||
* switches because it is the same class of control: a developer tool that a player has no reason
|
||||
* to find, next to the other things you turn on to diagnose rather than to play.
|
||||
*
|
||||
* The port is shown rather than edited. Changing it only matters when two emulators share a
|
||||
* machine, which does not happen on a handheld, and stating it is the part that is actually
|
||||
* needed — the listener is on loopback, so it does nothing until it is forwarded, and you cannot
|
||||
* forward a port you were not told. */
|
||||
@Composable
|
||||
private fun PineSection(state: MutableState<Settings>) {
|
||||
val s = state.value
|
||||
fun apply(updated: Settings) = InGameOverlay.saveSettings(updated)
|
||||
|
||||
CollapsibleSection(str("fixes.section.pine")) {
|
||||
HelpText(str("fixes.section.pine.help"))
|
||||
ToggleRow(
|
||||
str("fixes.pine.enable"),
|
||||
s.pineEnabled,
|
||||
description = "${str("fixes.pine.enable.desc")} (127.0.0.1:${s.pineSlot})",
|
||||
) { apply(s.copy(pineEnabled = it)) }
|
||||
if (s.pineEnabled) HelpText("adb forward tcp:${s.pineSlot} tcp:${s.pineSlot}")
|
||||
}
|
||||
}
|
||||
|
||||
// CollapsibleSection now lives in SettingsWidgets.kt (shared by the Fixes / Pad /
|
||||
// Performance / Renderer tabs).
|
||||
|
||||
|
||||
+1
-1
@@ -68,7 +68,7 @@ internal val SETTINGS_CATEGORY_FIELDS: Map<SettingsCategory, List<String>> = map
|
||||
// FixesTab.kt — also owns the GameDB fixes and the recompiler toggles, which moved here
|
||||
// from Performance and from the retired Recompiler tab.
|
||||
SettingsCategory.Advanced to listOf(
|
||||
"enableFastBoot", "enableGameFixes",
|
||||
"enableFastBoot", "enableGameFixes", "pineEnabled", "pineSlot",
|
||||
"gamefixBlitInternalFps", "gamefixDmaBusy", "gamefixEETiming", "gamefixFpuMul",
|
||||
"gamefixFullVu0Sync", "gamefixGifFifo", "gamefixGoemonTlb", "gamefixIbit",
|
||||
"gamefixInstantDma", "gamefixOphFlag", "gamefixSkipMpeg",
|
||||
|
||||
@@ -254,6 +254,8 @@ internal val SETTINGS_SEARCH_INDEX: List<SettingsSearchEntry> = listOf(
|
||||
SettingsSearchEntry("VU0", false, SettingsCategory.Advanced),
|
||||
SettingsSearchEntry("VU1", false, SettingsCategory.Advanced),
|
||||
SettingsSearchEntry("Fastmem", false, SettingsCategory.Advanced),
|
||||
SettingsSearchEntry("fixes.section.pine", true, SettingsCategory.Advanced),
|
||||
SettingsSearchEntry("fixes.pine.enable", true, SettingsCategory.Advanced),
|
||||
SettingsSearchEntry("patches.enablePatches.label", true, SettingsCategory.Patches),
|
||||
SettingsSearchEntry("patches.cheats.label", true, SettingsCategory.Patches),
|
||||
SettingsSearchEntry("patches.widescreen.label", true, SettingsCategory.Patches),
|
||||
|
||||
Reference in New Issue
Block a user