Implement DoAllPlayersHaveGame() check

This commit is contained in:
Tom Pratt
2026-05-12 12:58:44 -07:00
committed by Tom Pratt
parent 76ae445694
commit 4c0bf2944b
6 changed files with 61 additions and 2 deletions

View File

@@ -170,6 +170,8 @@ class NetplaySession(
fun changeGame(gameFile: GameFile) = nativeChangeGame(gameFile)
fun doAllPlayersHaveGame(): Boolean = nativeDoAllPlayersHaveGame()
fun startGame() = nativeStartGame()
fun getPort(): Int = nativeGetPort()
@@ -261,6 +263,8 @@ class NetplaySession(
private external fun nativeChangeGame(gameFile: GameFile)
private external fun nativeDoAllPlayersHaveGame(): Boolean
private external fun nativeStartGame()
private external fun nativeGetPort(): Int

View File

@@ -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 _notAllPlayersHaveGame = Channel<Unit>(Channel.CONFLATED)
val notAllPlayersHaveGame = _notAllPlayersHaveGame.receiveAsFlow()
fun startGame() {
if (netplaySession.doAllPlayersHaveGame()) {
netplaySession.startGame()
} else {
_notAllPlayersHaveGame.trySend(Unit)
}
}
fun confirmStartGame() {
netplaySession.startGame()
}

View File

@@ -9,7 +9,6 @@ import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.livedata.observeAsState
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.flowWithLifecycle
@@ -49,15 +48,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,
notAllPlayersHaveGame = viewModel.notAllPlayersHaveGame,
onConfirmStartGame = viewModel::confirmStartGame,
players = viewModel.players.collectAsState().value,
hostInputAuthorityEnabled = viewModel.hostInputAuthority.collectAsState().value,
networkMode = viewModel.networkMode.collectAsState().value,

View File

@@ -121,6 +121,8 @@ fun NetplayScreen(
onStartGame: () -> Unit,
onGameSelected: (GameFile) -> Unit,
gameFiles: List<GameFile>,
notAllPlayersHaveGame: Flow<Unit>,
onConfirmStartGame: () -> Unit,
hostInputAuthorityEnabled: Boolean,
networkMode: NetworkMode,
onNetworkModeChanged: (NetworkMode) -> Unit,
@@ -229,6 +231,11 @@ fun NetplayScreen(
fatalTraversalError.collect { traversalError = it }
}
var showNotAllPlayersHaveGame by rememberSaveable { mutableStateOf(false) }
LaunchedEffect(Unit) {
notAllPlayersHaveGame.collect { showNotAllPlayersHaveGame = true }
}
var dismissSaveTransferProgressDialog by rememberSaveable { mutableStateOf(false) }
if (saveTransferProgress == null) {
dismissSaveTransferProgressDialog = false
@@ -279,6 +286,27 @@ fun NetplayScreen(
onDismiss = { dismissGameDigestDialog = true },
)
}
showNotAllPlayersHaveGame -> {
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 = {
showNotAllPlayersHaveGame = false
onConfirmStartGame()
}) {
Text(stringResource(R.string.yes))
}
},
dismissButton = {
TextButton(onClick = { showNotAllPlayersHaveGame = false }) {
Text(stringResource(R.string.no))
}
},
onDismissRequest = { showNotAllPlayersHaveGame = false },
)
}
}
}
}
@@ -1280,6 +1308,8 @@ private fun PreviewNetplayScreen() {
onStartGame = {},
onGameSelected = {},
gameFiles = emptyList(),
notAllPlayersHaveGame = emptyFlow(),
onConfirmStartGame = {},
hostInputAuthorityEnabled = true,
networkMode = NetworkMode.HOST_INPUT_AUTHORITY,
onNetworkModeChanged = {},

View File

@@ -997,6 +997,8 @@ It can efficiently compress both junk data and encrypted Wii data.
<string name="netplay_port_label">Port</string>
<string name="netplay_title">Netplay</string>
<string name="netplay_start">Start</string>
<string name="netplay_start_warning_title">Warning</string>
<string name="netplay_start_warning_not_all_players_have_game">Not all players have the game. Do you really want to start?</string>
<string name="netplay_chat_label">Chat</string>
<string name="netplay_chat_send">Send</string>
<string name="netplay_message_game_changed">Game changed to %1$s</string>

View File

@@ -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<jboolean>(client->DoAllPlayersHaveGame());
return JNI_TRUE;
}
JNIEXPORT void JNICALL
Java_org_dolphinemu_dolphinemu_features_netplay_NetplaySession_nativeStartGame(JNIEnv* env,
jobject obj)