From 1c2806dfe9d6d644a1423ccced319d0ac7dea632 Mon Sep 17 00:00:00 2001 From: Tom Pratt Date: Tue, 5 May 2026 21:50:04 +0200 Subject: [PATCH] Add host buffer settings for fair input delay mode Also rename max buffer to client buffer for better consistency with settings and c++ --- .../features/netplay/NetplaySession.kt | 10 ++- .../netplay/model/NetplayViewModel.kt | 21 ++++-- .../features/netplay/ui/NetplayActivity.kt | 6 +- .../features/netplay/ui/NetplayScreen.kt | 72 +++++++++++++------ .../features/settings/model/IntSetting.kt | 6 ++ .../app/src/main/res/values/strings.xml | 3 +- Source/Android/jni/NetPlay/Netplay.cpp | 10 ++- 7 files changed, 93 insertions(+), 35 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 d8f2ce8860..c5795edf63 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 @@ -49,7 +49,7 @@ class NetplaySession( @Volatile var isClosed = false private set - + val isHosting: Boolean get() = netPlayServerPointer != 0L @@ -162,7 +162,9 @@ class NetplaySession( nativeSendMessage(message) } - fun adjustPadBufferSize(buffer: Int) = nativeAdjustPadBufferSize(buffer) + fun adjustClientPadBufferSize(buffer: Int) = nativeAdjustClientPadBufferSize(buffer) + + fun adjustServerPadBufferSize(buffer: Int) = nativeAdjustServerPadBufferSize(buffer) fun changeGame(gameFile: GameFile) = nativeChangeGame(gameFile) @@ -241,7 +243,9 @@ class NetplaySession( private external fun nativeSendMessage(message: String) - private external fun nativeAdjustPadBufferSize(buffer: Int) + private external fun nativeAdjustClientPadBufferSize(buffer: Int) + + private external fun nativeAdjustServerPadBufferSize(buffer: Int) private external fun nativeReleaseUICallbacks(pointer: Long) 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 4ebea7e283..ea8ac9dea5 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,8 +65,11 @@ class NetplayViewModel( val hostInputAuthority = netplaySession.hostInputAuthorityEnabled .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false) - private val _maxBuffer = MutableStateFlow(IntSetting.NETPLAY_CLIENT_BUFFER_SIZE.int) - val maxBuffer = _maxBuffer.asStateFlow() + private val _buffer = MutableStateFlow(IntSetting.NETPLAY_BUFFER_SIZE.int) + val buffer = _buffer.asStateFlow() + + private val _clientBuffer = MutableStateFlow(IntSetting.NETPLAY_CLIENT_BUFFER_SIZE.int) + val clientBuffer = _clientBuffer.asStateFlow() val gameFiles = GameFileCacheManager.getGameFiles().asFlow() .map { it.toList() } @@ -104,10 +107,16 @@ class NetplayViewModel( netplaySession.sendMessage(trimmedMessage) } - fun setMaxBuffer(buffer: Int) { - _maxBuffer.value = buffer - IntSetting.NETPLAY_CLIENT_BUFFER_SIZE.setInt(NativeConfig.LAYER_BASE, buffer) - netplaySession.adjustPadBufferSize(buffer) + fun setBuffer(value: Int) { + _buffer.value = value + IntSetting.NETPLAY_BUFFER_SIZE.setInt(NativeConfig.LAYER_BASE, value) + netplaySession.adjustServerPadBufferSize(value) + } + + fun setClientBuffer(value: Int) { + _clientBuffer.value = value + IntSetting.NETPLAY_CLIENT_BUFFER_SIZE.setInt(NativeConfig.LAYER_BASE, value) + netplaySession.adjustClientPadBufferSize(value) } fun changeGame(gameFile: GameFile) { 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 e45ba7e7c1..bae20aee46 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,8 +60,10 @@ class NetplayActivity : AppCompatActivity(), ThemeProvider { gameFiles = viewModel.gameFiles.collectAsState().value, players = viewModel.players.collectAsState().value, hostInputAuthorityEnabled = viewModel.hostInputAuthority.collectAsState().value, - maxBuffer = viewModel.maxBuffer.collectAsState().value, - onMaxBufferChanged = viewModel::setMaxBuffer, + buffer = viewModel.buffer.collectAsState().value, + onBufferChanged = viewModel::setBuffer, + clientBuffer = viewModel.clientBuffer.collectAsState().value, + onClientBufferChanged = viewModel::setClientBuffer, saveTransferProgress = viewModel.saveTransferProgress.collectAsState().value, gameDigestProgress = viewModel.gameDigestProgress.collectAsState().value, joinAddresses = viewModel.joinAddresses.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 71b427a8c8..e68e6ff7d2 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 @@ -121,8 +121,10 @@ fun NetplayScreen( onGameSelected: (GameFile) -> Unit, gameFiles: List, hostInputAuthorityEnabled: Boolean, - maxBuffer: Int, - onMaxBufferChanged: (Int) -> Unit, + buffer: Int, + onBufferChanged: (Int) -> Unit, + clientBuffer: Int, + onClientBufferChanged: (Int) -> Unit, players: List, saveTransferProgress: SaveTransferProgress?, gameDigestProgress: GameDigestProgress?, @@ -176,8 +178,10 @@ fun NetplayScreen( onShowGamePickerChanged = { showGamePicker = it }, players = players, hostInputAuthorityEnabled = hostInputAuthorityEnabled, - maxBuffer = maxBuffer, - onMaxBufferChanged = onMaxBufferChanged, + buffer = buffer, + onBufferChanged = onBufferChanged, + clientBuffer = clientBuffer, + onClientBufferChanged = onClientBufferChanged, joinAddresses = joinAddresses, selectedJoinInfoType = selectedJoinInfoType, onSelectedJoinInfoTypeChanged = { selectedJoinInfoType = it }, @@ -197,8 +201,10 @@ fun NetplayScreen( onShowGamePickerChanged = { showGamePicker = it }, players = players, hostInputAuthorityEnabled = hostInputAuthorityEnabled, - maxBuffer = maxBuffer, - onMaxBufferChanged = onMaxBufferChanged, + buffer = buffer, + onBufferChanged = onBufferChanged, + clientBuffer = clientBuffer, + onClientBufferChanged = onClientBufferChanged, joinAddresses = joinAddresses, selectedJoinInfoType = selectedJoinInfoType, onSelectedJoinInfoTypeChanged = { selectedJoinInfoType = it }, @@ -284,8 +290,10 @@ private fun PortraitContent( onShowGamePickerChanged: (Boolean) -> Unit, players: List, hostInputAuthorityEnabled: Boolean, - maxBuffer: Int, - onMaxBufferChanged: (Int) -> Unit, + buffer: Int, + onBufferChanged: (Int) -> Unit, + clientBuffer: Int, + onClientBufferChanged: (Int) -> Unit, joinAddresses: Map, selectedJoinInfoType: JoinInfoType, onSelectedJoinInfoTypeChanged: (JoinInfoType) -> Unit, @@ -316,8 +324,10 @@ private fun PortraitContent( onShowGamePickerChanged = onShowGamePickerChanged, players = players, hostInputAuthorityEnabled = hostInputAuthorityEnabled, - maxBuffer = maxBuffer, - onMaxBufferChanged = onMaxBufferChanged, + buffer = buffer, + onBufferChanged = onBufferChanged, + clientBuffer = clientBuffer, + onClientBufferChanged = onClientBufferChanged, isHosting = isHosting, joinAddresses = joinAddresses, selectedJoinInfoType = selectedJoinInfoType, @@ -346,8 +356,10 @@ private fun LandscapeContent( onShowGamePickerChanged: (Boolean) -> Unit, players: List, hostInputAuthorityEnabled: Boolean, - maxBuffer: Int, - onMaxBufferChanged: (Int) -> Unit, + buffer: Int, + onBufferChanged: (Int) -> Unit, + clientBuffer: Int, + onClientBufferChanged: (Int) -> Unit, joinAddresses: Map, selectedJoinInfoType: JoinInfoType, onSelectedJoinInfoTypeChanged: (JoinInfoType) -> Unit, @@ -382,8 +394,10 @@ private fun LandscapeContent( onShowGamePickerChanged = onShowGamePickerChanged, players = players, hostInputAuthorityEnabled = hostInputAuthorityEnabled, - maxBuffer = maxBuffer, - onMaxBufferChanged = onMaxBufferChanged, + buffer = buffer, + onBufferChanged = onBufferChanged, + clientBuffer = clientBuffer, + onClientBufferChanged = onClientBufferChanged, isHosting = isHosting, joinAddresses = joinAddresses, selectedJoinInfoType = selectedJoinInfoType, @@ -407,8 +421,10 @@ private fun PlayersAndSettings( onShowGamePickerChanged: (Boolean) -> Unit, players: List, hostInputAuthorityEnabled: Boolean, - maxBuffer: Int, - onMaxBufferChanged: (Int) -> Unit, + buffer: Int, + onBufferChanged: (Int) -> Unit, + clientBuffer: Int, + onClientBufferChanged: (Int) -> Unit, isHosting: Boolean, joinAddresses: Map, selectedJoinInfoType: JoinInfoType, @@ -459,13 +475,23 @@ private fun PlayersAndSettings( ) } - if (hostInputAuthorityEnabled) { + if (isHosting && !hostInputAuthorityEnabled) { MenuSpacer() BufferInput( - value = maxBuffer, - onValueChange = onMaxBufferChanged, - label = stringResource(R.string.netplay_max_buffer), + value = buffer, + onValueChange = onBufferChanged, + label = stringResource(R.string.netplay_buffer), + ) + } + + if (!isHosting && hostInputAuthorityEnabled) { + MenuSpacer() + + BufferInput( + value = clientBuffer, + onValueChange = onClientBufferChanged, + label = stringResource(R.string.netplay_client_buffer), ) } } @@ -1188,8 +1214,10 @@ private fun PreviewNetplayScreen() { onGameSelected = {}, gameFiles = emptyList(), hostInputAuthorityEnabled = true, - maxBuffer = 10, - onMaxBufferChanged = {}, + buffer = 5, + onBufferChanged = {}, + clientBuffer = 10, + onClientBufferChanged = {}, saveTransferProgress = null, gameDigestProgress = null, joinAddresses = mapOf( diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/IntSetting.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/IntSetting.kt index 85f265442b..628e286b49 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/IntSetting.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/IntSetting.kt @@ -146,6 +146,12 @@ enum class IntSetting( Settings.SECTION_INI_NETPLAY, "BufferSizeClient", 1 + ), + NETPLAY_BUFFER_SIZE( + Settings.FILE_DOLPHIN, + Settings.SECTION_INI_NETPLAY, + "BufferSize", + 5 ); override val isOverridden: Boolean diff --git a/Source/Android/app/src/main/res/values/strings.xml b/Source/Android/app/src/main/res/values/strings.xml index fbc664f4ef..09abe850fb 100644 --- a/Source/Android/app/src/main/res/values/strings.xml +++ b/Source/Android/app/src/main/res/values/strings.xml @@ -1008,7 +1008,8 @@ It can efficiently compress both junk data and encrypted Wii data. Name Ping Mapping - Max buffer + Buffer + Max buffer Netplay connection lost Close The hashes match diff --git a/Source/Android/jni/NetPlay/Netplay.cpp b/Source/Android/jni/NetPlay/Netplay.cpp index 8ed026c9c8..e845f8ec60 100644 --- a/Source/Android/jni/NetPlay/Netplay.cpp +++ b/Source/Android/jni/NetPlay/Netplay.cpp @@ -50,7 +50,7 @@ Java_org_dolphinemu_dolphinemu_features_netplay_NetplaySession_nativeSendMessage } JNIEXPORT void JNICALL -Java_org_dolphinemu_dolphinemu_features_netplay_NetplaySession_nativeAdjustPadBufferSize(JNIEnv* env, +Java_org_dolphinemu_dolphinemu_features_netplay_NetplaySession_nativeAdjustClientPadBufferSize(JNIEnv* env, jobject obj, jint buffer) { @@ -58,6 +58,14 @@ Java_org_dolphinemu_dolphinemu_features_netplay_NetplaySession_nativeAdjustPadBu client->AdjustPadBufferSize(static_cast(buffer)); } +JNIEXPORT void JNICALL +Java_org_dolphinemu_dolphinemu_features_netplay_NetplaySession_nativeAdjustServerPadBufferSize( + JNIEnv* env, jobject obj, jint buffer) +{ + if (auto* server = GetServerPointer(env, obj)) + server->AdjustPadBufferSize(static_cast(buffer)); +} + JNIEXPORT jlong JNICALL Java_org_dolphinemu_dolphinemu_features_netplay_NetplaySession_nativeCreateUICallbacks(JNIEnv* env, jobject obj)