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 65a7e2c10e..0efabc7f0f 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 @@ -166,6 +166,8 @@ class NetplaySession( fun changeGame(gameFile: GameFile) = nativeChangeGame(gameFile) + fun doAllPlayersHaveGame(): Boolean = nativeDoAllPlayersHaveGame() + fun startGame() = nativeStartGame() fun getPort(): Int = nativeGetPort() @@ -257,6 +259,8 @@ class NetplaySession( private external fun nativeChangeGame(gameFile: GameFile) + private external fun nativeDoAllPlayersHaveGame(): Boolean + private external fun nativeStartGame() private external fun nativeGetPort(): 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 9f9b422f4b..1e02936835 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 @@ -9,7 +9,9 @@ import androidx.lifecycle.viewModelScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.launchIn @@ -99,7 +101,18 @@ class NetplayViewModel( } } + private val _startGameWarning = Channel(Channel.CONFLATED) + val startGameWarning = _startGameWarning.receiveAsFlow() + fun startGame() { + if (netplaySession.doAllPlayersHaveGame()) { + netplaySession.startGame() + } else { + _startGameWarning.trySend(Unit) + } + } + + fun confirmStartGame() { netplaySession.startGame() } 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 fe38cfe067..1905db24fa 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 @@ -49,15 +49,17 @@ class NetplayActivity : AppCompatActivity(), ThemeProvider { DolphinTheme { NetplayScreen( onBackClicked = { finish() }, + isHosting = viewModel.isHosting, connectionLost = viewModel.connectionLost, fatalTraversalError = viewModel.fatalTraversalError, messages = viewModel.messages.collectAsState().value, onSendMessage = viewModel::sendMessage, game = viewModel.game.collectAsState().value, - isHosting = viewModel.isHosting, onStartGame = viewModel::startGame, onGameSelected = viewModel::changeGame, gameFiles = viewModel.gameFiles.collectAsState().value, + startGameWarning = viewModel.startGameWarning, + onConfirmStartGame = viewModel::confirmStartGame, players = viewModel.players.collectAsState().value, hostInputAuthorityEnabled = viewModel.hostInputAuthority.collectAsState().value, networkMode = viewModel.networkMode.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 de1f0d16a4..6613a719c0 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,6 +121,8 @@ fun NetplayScreen( onStartGame: () -> Unit, onGameSelected: (GameFile) -> Unit, gameFiles: List, + startGameWarning: Flow, + onConfirmStartGame: () -> Unit, hostInputAuthorityEnabled: Boolean, networkMode: NetworkMode, onNetworkModeChanged: (NetworkMode) -> Unit, @@ -229,6 +231,11 @@ fun NetplayScreen( fatalTraversalError.collect { traversalError = it } } + var showStartGameWarning by rememberSaveable { mutableStateOf(false) } + LaunchedEffect(Unit) { + startGameWarning.collect { showStartGameWarning = true } + } + var dismissSaveTransferProgressDialog by rememberSaveable { mutableStateOf(false) } if (saveTransferProgress == null) { dismissSaveTransferProgressDialog = false @@ -279,6 +286,27 @@ fun NetplayScreen( onDismiss = { dismissGameDigestDialog = true }, ) } + + showStartGameWarning -> { + AlertDialog( + title = { Text(stringResource(R.string.netplay_start_warning_title)) }, + text = { Text(stringResource(R.string.netplay_start_warning_not_all_players_have_game)) }, + confirmButton = { + TextButton(onClick = { + showStartGameWarning = false + onConfirmStartGame() + }) { + Text(stringResource(R.string.yes)) + } + }, + dismissButton = { + TextButton(onClick = { showStartGameWarning = false }) { + Text(stringResource(R.string.no)) + } + }, + onDismissRequest = { showStartGameWarning = false }, + ) + } } } } @@ -1280,6 +1308,8 @@ private fun PreviewNetplayScreen() { onStartGame = {}, onGameSelected = {}, gameFiles = emptyList(), + startGameWarning = emptyFlow(), + onConfirmStartGame = {}, hostInputAuthorityEnabled = true, networkMode = NetworkMode.HOST_INPUT_AUTHORITY, onNetworkModeChanged = {}, diff --git a/Source/Android/app/src/main/res/values/strings.xml b/Source/Android/app/src/main/res/values/strings.xml index 6837e951fe..58bce8c595 100644 --- a/Source/Android/app/src/main/res/values/strings.xml +++ b/Source/Android/app/src/main/res/values/strings.xml @@ -997,6 +997,8 @@ It can efficiently compress both junk data and encrypted Wii data. Port Netplay Start + Warning + Not all players have the game. Do you really want to start? Chat Send Game changed to %1$s diff --git a/Source/Android/jni/NetPlay/Netplay.cpp b/Source/Android/jni/NetPlay/Netplay.cpp index b19e1a3c9d..736f4e0109 100644 --- a/Source/Android/jni/NetPlay/Netplay.cpp +++ b/Source/Android/jni/NetPlay/Netplay.cpp @@ -181,6 +181,15 @@ Java_org_dolphinemu_dolphinemu_features_netplay_NetplaySession_nativeChangeGame( server->ChangeGame(game_file->GetSyncIdentifier(), game_file->GetLongName()); } +JNIEXPORT jboolean JNICALL +Java_org_dolphinemu_dolphinemu_features_netplay_NetplaySession_nativeDoAllPlayersHaveGame( + JNIEnv* env, jobject obj) +{ + if (auto* client = GetClientPointer(env, obj)) + return static_cast(client->DoAllPlayersHaveGame()); + return JNI_TRUE; +} + JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_features_netplay_NetplaySession_nativeStartGame(JNIEnv* env, jobject obj)