summaryrefslogtreecommitdiff
path: root/Source/Android/app/src
diff options
context:
space:
mode:
authorTom Pratt <tom.pratt@outlook.com>2026-05-06 09:46:33 +0200
committerTom Pratt <tompratt@squareup.com>2026-05-19 12:03:00 +0200
commit76ae44569415c0ffb674d184312ea898aab92a18 (patch)
treebb4fa81127339de90382aae45166b0e58a2fbc1d /Source/Android/app/src
parent1c2806dfe9d6d644a1423ccced319d0ac7dea632 (diff)
Add network mode picker for host
Diffstat (limited to 'Source/Android/app/src')
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/NetplaySession.kt4
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/model/NetplayViewModel.kt11
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/model/NetworkMode.kt18
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/ui/NetplayActivity.kt2
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/ui/NetplayScreen.kt69
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/StringSetting.kt3
-rw-r--r--Source/Android/app/src/main/res/values/strings.xml4
7 files changed, 110 insertions, 1 deletions
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/NetplaySession.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/NetplaySession.kt
index c5795edf63..0ba5d409b0 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/NetplaySession.kt
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/NetplaySession.kt
@@ -162,6 +162,8 @@ class NetplaySession(
nativeSendMessage(message)
}
+ fun setHostInputAuthority(enable: Boolean) = nativeSetHostInputAuthority(enable)
+
fun adjustClientPadBufferSize(buffer: Int) = nativeAdjustClientPadBufferSize(buffer)
fun adjustServerPadBufferSize(buffer: Int) = nativeAdjustServerPadBufferSize(buffer)
@@ -243,6 +245,8 @@ class NetplaySession(
private external fun nativeSendMessage(message: String)
+ private external fun nativeSetHostInputAuthority(enable: Boolean)
+
private external fun nativeAdjustClientPadBufferSize(buffer: Int)
private external fun nativeAdjustServerPadBufferSize(buffer: Int)
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/model/NetplayViewModel.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/model/NetplayViewModel.kt
index ea8ac9dea5..9f9b422f4b 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/model/NetplayViewModel.kt
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/model/NetplayViewModel.kt
@@ -65,6 +65,11 @@ class NetplayViewModel(
val hostInputAuthority = netplaySession.hostInputAuthorityEnabled
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
+ private val _networkMode = MutableStateFlow(
+ NetworkMode.fromConfigValue(StringSetting.NETPLAY_NETWORK_MODE.string)
+ )
+ val networkMode = _networkMode.asStateFlow()
+
private val _buffer = MutableStateFlow(IntSetting.NETPLAY_BUFFER_SIZE.int)
val buffer = _buffer.asStateFlow()
@@ -107,6 +112,12 @@ class NetplayViewModel(
netplaySession.sendMessage(trimmedMessage)
}
+ fun setNetworkMode(mode: NetworkMode) {
+ _networkMode.value = mode
+ StringSetting.NETPLAY_NETWORK_MODE.setString(NativeConfig.LAYER_BASE, mode.configValue)
+ netplaySession.setHostInputAuthority(mode.isHostInputAuthority)
+ }
+
fun setBuffer(value: Int) {
_buffer.value = value
IntSetting.NETPLAY_BUFFER_SIZE.setInt(NativeConfig.LAYER_BASE, value)
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/model/NetworkMode.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/model/NetworkMode.kt
new file mode 100644
index 0000000000..55d29f5f17
--- /dev/null
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/model/NetworkMode.kt
@@ -0,0 +1,18 @@
+package org.dolphinemu.dolphinemu.features.netplay.model
+
+import androidx.annotation.StringRes
+import org.dolphinemu.dolphinemu.R
+
+enum class NetworkMode(val configValue: String, @StringRes val labelId: Int) {
+ FAIR_INPUT_DELAY("fixeddelay", R.string.netplay_network_mode_fair_input_delay),
+ HOST_INPUT_AUTHORITY("hostinputauthority", R.string.netplay_network_mode_host_input_authority),
+ GOLF("golf", R.string.netplay_network_mode_golf);
+
+ val isHostInputAuthority: Boolean
+ get() = this == HOST_INPUT_AUTHORITY || this == GOLF
+
+ companion object {
+ fun fromConfigValue(value: String): NetworkMode =
+ entries.find { it.configValue == value } ?: FAIR_INPUT_DELAY
+ }
+}
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/ui/NetplayActivity.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/ui/NetplayActivity.kt
index bae20aee46..fe38cfe067 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/ui/NetplayActivity.kt
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/ui/NetplayActivity.kt
@@ -60,6 +60,8 @@ class NetplayActivity : AppCompatActivity(), ThemeProvider {
gameFiles = viewModel.gameFiles.collectAsState().value,
players = viewModel.players.collectAsState().value,
hostInputAuthorityEnabled = viewModel.hostInputAuthority.collectAsState().value,
+ networkMode = viewModel.networkMode.collectAsState().value,
+ onNetworkModeChanged = viewModel::setNetworkMode,
buffer = viewModel.buffer.collectAsState().value,
onBufferChanged = viewModel::setBuffer,
clientBuffer = viewModel.clientBuffer.collectAsState().value,
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/ui/NetplayScreen.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/ui/NetplayScreen.kt
index e68e6ff7d2..3be5cb0618 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/ui/NetplayScreen.kt
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/ui/NetplayScreen.kt
@@ -95,6 +95,7 @@ import org.dolphinemu.dolphinemu.features.netplay.model.GameDigestProgress
import org.dolphinemu.dolphinemu.features.netplay.model.JoinAddress
import org.dolphinemu.dolphinemu.features.netplay.model.JoinInfoType
import org.dolphinemu.dolphinemu.features.netplay.model.NetplayMessage
+import org.dolphinemu.dolphinemu.features.netplay.model.NetworkMode
import org.dolphinemu.dolphinemu.features.netplay.model.Player
import org.dolphinemu.dolphinemu.features.netplay.model.SaveTransferProgress
import org.dolphinemu.dolphinemu.features.netplay.model.TraversalState
@@ -121,6 +122,8 @@ fun NetplayScreen(
onGameSelected: (GameFile) -> Unit,
gameFiles: List<GameFile>,
hostInputAuthorityEnabled: Boolean,
+ networkMode: NetworkMode,
+ onNetworkModeChanged: (NetworkMode) -> Unit,
buffer: Int,
onBufferChanged: (Int) -> Unit,
clientBuffer: Int,
@@ -178,6 +181,8 @@ fun NetplayScreen(
onShowGamePickerChanged = { showGamePicker = it },
players = players,
hostInputAuthorityEnabled = hostInputAuthorityEnabled,
+ networkMode = networkMode,
+ onNetworkModeChanged = onNetworkModeChanged,
buffer = buffer,
onBufferChanged = onBufferChanged,
clientBuffer = clientBuffer,
@@ -201,6 +206,8 @@ fun NetplayScreen(
onShowGamePickerChanged = { showGamePicker = it },
players = players,
hostInputAuthorityEnabled = hostInputAuthorityEnabled,
+ networkMode = networkMode,
+ onNetworkModeChanged = onNetworkModeChanged,
buffer = buffer,
onBufferChanged = onBufferChanged,
clientBuffer = clientBuffer,
@@ -290,6 +297,8 @@ private fun PortraitContent(
onShowGamePickerChanged: (Boolean) -> Unit,
players: List<Player>,
hostInputAuthorityEnabled: Boolean,
+ networkMode: NetworkMode,
+ onNetworkModeChanged: (NetworkMode) -> Unit,
buffer: Int,
onBufferChanged: (Int) -> Unit,
clientBuffer: Int,
@@ -324,6 +333,8 @@ private fun PortraitContent(
onShowGamePickerChanged = onShowGamePickerChanged,
players = players,
hostInputAuthorityEnabled = hostInputAuthorityEnabled,
+ networkMode = networkMode,
+ onNetworkModeChanged = onNetworkModeChanged,
buffer = buffer,
onBufferChanged = onBufferChanged,
clientBuffer = clientBuffer,
@@ -356,6 +367,8 @@ private fun LandscapeContent(
onShowGamePickerChanged: (Boolean) -> Unit,
players: List<Player>,
hostInputAuthorityEnabled: Boolean,
+ networkMode: NetworkMode,
+ onNetworkModeChanged: (NetworkMode) -> Unit,
buffer: Int,
onBufferChanged: (Int) -> Unit,
clientBuffer: Int,
@@ -394,6 +407,8 @@ private fun LandscapeContent(
onShowGamePickerChanged = onShowGamePickerChanged,
players = players,
hostInputAuthorityEnabled = hostInputAuthorityEnabled,
+ networkMode = networkMode,
+ onNetworkModeChanged = onNetworkModeChanged,
buffer = buffer,
onBufferChanged = onBufferChanged,
clientBuffer = clientBuffer,
@@ -421,6 +436,8 @@ private fun PlayersAndSettings(
onShowGamePickerChanged: (Boolean) -> Unit,
players: List<Player>,
hostInputAuthorityEnabled: Boolean,
+ networkMode: NetworkMode,
+ onNetworkModeChanged: (NetworkMode) -> Unit,
buffer: Int,
onBufferChanged: (Int) -> Unit,
clientBuffer: Int,
@@ -475,6 +492,15 @@ private fun PlayersAndSettings(
)
}
+ if (isHosting) {
+ MenuSpacer()
+
+ NetworkModeDropdown(
+ networkMode = networkMode,
+ onNetworkModeChanged = onNetworkModeChanged,
+ )
+ }
+
if (isHosting && !hostInputAuthorityEnabled) {
MenuSpacer()
@@ -902,6 +928,47 @@ private fun PlayersTable(
}
}
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+private fun NetworkModeDropdown(
+ networkMode: NetworkMode,
+ onNetworkModeChanged: (NetworkMode) -> Unit,
+) {
+ var expanded by remember { mutableStateOf(false) }
+
+ ExposedDropdownMenuBox(
+ expanded = expanded,
+ onExpandedChange = { expanded = it },
+ ) {
+ OutlinedTextField(
+ value = stringResource(networkMode.labelId),
+ onValueChange = {},
+ readOnly = true,
+ label = { Text(stringResource(R.string.netplay_network_mode_label)) },
+ trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) },
+ colors = ExposedDropdownMenuDefaults.outlinedTextFieldColors(),
+ modifier = Modifier
+ .menuAnchor(MenuAnchorType.PrimaryNotEditable)
+ .fillMaxWidth(),
+ )
+ ExposedDropdownMenu(
+ expanded = expanded,
+ onDismissRequest = { expanded = false },
+ ) {
+ // No golf mode for now since it requires in game UI.
+ listOf(NetworkMode.FAIR_INPUT_DELAY, NetworkMode.HOST_INPUT_AUTHORITY).forEach { mode ->
+ DropdownMenuItem(
+ text = { Text(stringResource(mode.labelId)) },
+ onClick = {
+ onNetworkModeChanged(mode)
+ expanded = false
+ },
+ )
+ }
+ }
+ }
+}
+
@Composable
private fun BufferInput(
value: Int,
@@ -1214,6 +1281,8 @@ private fun PreviewNetplayScreen() {
onGameSelected = {},
gameFiles = emptyList(),
hostInputAuthorityEnabled = true,
+ networkMode = NetworkMode.HOST_INPUT_AUTHORITY,
+ onNetworkModeChanged = {},
buffer = 5,
onBufferChanged = {},
clientBuffer = 10,
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/StringSetting.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/StringSetting.kt
index 610f45b2a3..72877429af 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/StringSetting.kt
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/StringSetting.kt
@@ -116,7 +116,8 @@ enum class StringSetting(
),
NETPLAY_ADDRESS(Settings.FILE_DOLPHIN, Settings.SECTION_INI_NETPLAY, "Address", "127.0.0.1"),
NETPLAY_NICKNAME(Settings.FILE_DOLPHIN, Settings.SECTION_INI_NETPLAY, "Nickname", "Player"),
- NETPLAY_GAME(Settings.FILE_DOLPHIN, Settings.SECTION_INI_NETPLAY, "Game", "");
+ NETPLAY_GAME(Settings.FILE_DOLPHIN, Settings.SECTION_INI_NETPLAY, "Game", ""),
+ NETPLAY_NETWORK_MODE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_NETPLAY, "NetworkMode", "fixeddelay");
override val isOverridden: Boolean
get() = NativeConfig.isOverridden(file, section, key)
diff --git a/Source/Android/app/src/main/res/values/strings.xml b/Source/Android/app/src/main/res/values/strings.xml
index 09abe850fb..6837e951fe 100644
--- a/Source/Android/app/src/main/res/values/strings.xml
+++ b/Source/Android/app/src/main/res/values/strings.xml
@@ -1008,6 +1008,10 @@ It can efficiently compress both junk data and encrypted Wii data.
<string name="netplay_players_name">Name</string>
<string name="netplay_players_ping">Ping</string>
<string name="netplay_players_mapping">Mapping</string>
+ <string name="netplay_network_mode_label">Input mode</string>
+ <string name="netplay_network_mode_fair_input_delay">Fair Input Delay</string>
+ <string name="netplay_network_mode_host_input_authority">Host Input Authority</string>
+ <string name="netplay_network_mode_golf">Golf Mode</string>
<string name="netplay_buffer">Buffer</string>
<string name="netplay_client_buffer">Max buffer</string>
<string name="netplay_connection_lost">Netplay connection lost</string>