summaryrefslogtreecommitdiff
path: root/Source/Android/app/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'Source/Android/app/src/main/java')
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.kt2
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/NetplayManager.kt38
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/NetplaySession.kt (renamed from Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/Netplay.kt)140
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/model/NetplaySetupViewModel.kt52
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/model/NetplayViewModel.kt47
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/ui/NetplayActivity.kt11
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/ui/NetplaySetupActivity.kt6
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.kt15
8 files changed, 195 insertions, 116 deletions
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.kt
index 2e2c295c7d..b52b7b4fa4 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.kt
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.kt
@@ -346,7 +346,7 @@ object NativeLibrary {
* Begins emulation for a netplay session, using the BootSessionData provided by the host.
*/
@JvmStatic
- external fun RunNetPlay(paths: Array<String>, riivolution: Boolean)
+ external fun RunNetPlay(paths: Array<String>, riivolution: Boolean, bootSessionDataPointer: Long)
@JvmStatic
external fun ChangeDisc(path: String)
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/NetplayManager.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/NetplayManager.kt
new file mode 100644
index 0000000000..eae44e65be
--- /dev/null
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/NetplayManager.kt
@@ -0,0 +1,38 @@
+// Copyright 2003 Dolphin Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+package org.dolphinemu.dolphinemu.features.netplay
+
+import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.sync.Mutex
+import kotlinx.coroutines.sync.withLock
+
+object NetplayManager {
+
+ private val mutex = Mutex()
+
+ @Volatile
+ private var closeComplete: CompletableDeferred<Unit>? = null
+
+ @Volatile
+ var activeSession: NetplaySession? = null
+ private set
+
+ suspend fun createSession(): NetplaySession = mutex.withLock {
+ closeComplete?.await()
+
+ // Sessions should be closed by UI navigation, but just in case.
+ activeSession?.closeBlocking()
+
+ closeComplete = CompletableDeferred()
+
+ NetplaySession(
+ onClosed = {
+ activeSession = null
+ closeComplete?.complete(Unit)
+ }
+ ).also {
+ activeSession = it
+ }
+ }
+}
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/Netplay.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/NetplaySession.kt
index 1cec94f19d..f47d9ab198 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/Netplay.kt
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/NetplaySession.kt
@@ -6,7 +6,6 @@ package org.dolphinemu.dolphinemu.features.netplay
import androidx.annotation.Keep
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.channels.BufferOverflow
@@ -29,14 +28,21 @@ import org.dolphinemu.dolphinemu.features.netplay.model.NetplayMessage
import org.dolphinemu.dolphinemu.features.netplay.model.Player
import org.dolphinemu.dolphinemu.features.netplay.model.SaveTransferProgress
-object Netplay {
- @Keep
+class NetplaySession(
+ private val onClosed: (NetplaySession) -> Unit,
+) {
+
+ private var netPlayUICallbacksPointer: Long = nativeCreateUICallbacks()
+
private var netPlayClientPointer: Long = 0
- @Keep
private var bootSessionDataPointer: Long = 0
- private var sessionScope: CoroutineScope? = null
+ private val sessionScope = CoroutineScope(SupervisorJob())
+
+ @Volatile
+ var isClosed = false
+ private set
val isLaunching: Boolean
get() = bootSessionDataPointer != 0L
@@ -93,97 +99,96 @@ object Netplay {
val saveTransferProgress = _saveTransferProgress.asStateFlow()
suspend fun join(): Boolean = withContext(Dispatchers.IO) {
- val scope = createSessionScope()
+ if (isClosed) throw IllegalStateException("Cannot join a closed session")
- // Gather all messages that should appear in the chat window.
mergeMessages()
.runningFold(emptyList<NetplayMessage>()) { acc, msg -> listOf(msg) + acc }
.onEach { _messages.tryEmit(it) }
- .launchIn(scope)
+ .launchIn(sessionScope)
- netPlayClientPointer = Join()
- val isConnected = netPlayClientPointer != 0L && isClientConnected()
+ netPlayClientPointer = nativeJoin()
- if (!isActive) {
- releaseNetplayClient()
+ if (netPlayClientPointer == 0L || !isActive) {
+ closeBlocking()
return@withContext false
}
- if (isConnected) {
- return@withContext true
+ true
+ }
+
+ fun sendMessage(message: String) = nativeSendMessage(message)
+
+ fun adjustPadBufferSize(buffer: Int) = nativeAdjustPadBufferSize(buffer)
+
+ fun consumeBootSessionData(): Long {
+ return bootSessionDataPointer.also {
+ bootSessionDataPointer = 0
}
+ }
- releaseNetplayClient()
- false
+ suspend fun close() = withContext(Dispatchers.IO) {
+ closeBlocking()
}
- suspend fun quit() = withContext(Dispatchers.IO) {
- releaseNetplayClient()
+ @Synchronized
+ fun closeBlocking() {
+ if (isClosed) return
+ isClosed = true
+ sessionScope.cancel()
+ releaseNativeResources()
+ onClosed(this)
}
- @OptIn(ExperimentalCoroutinesApi::class)
- private fun releaseNetplayClient() {
- sessionScope?.cancel()
- sessionScope = null
+ protected fun finalize() {
+ releaseNativeResources()
+ }
- if (bootSessionDataPointer != 0L) {
- ReleaseBootSessionData()
+ private fun mergeMessages(): Flow<NetplayMessage> = merge(
+ chatMessages.map { NetplayMessage.Chat(it) },
+ game.map { NetplayMessage.GameChanged(it) },
+ hostInputAuthorityEnabled.map { NetplayMessage.HostInputAuthorityChanged(it) },
+ padBuffer.map { NetplayMessage.BufferChanged(it) },
+ )
+
+ private fun releaseNativeResources() {
+ val currentBootSessionDataPointer = bootSessionDataPointer
+ if (currentBootSessionDataPointer != 0L) {
bootSessionDataPointer = 0
+ nativeReleaseBootSessionData(currentBootSessionDataPointer)
}
- if (netPlayClientPointer != 0L) {
- ReleaseNetplayClient()
+ val currentNetPlayClientPointer = netPlayClientPointer
+ if (currentNetPlayClientPointer != 0L) {
netPlayClientPointer = 0
+ nativeReleaseClient(currentNetPlayClientPointer)
}
- _launchGame.flush()
- _stopGame.flush()
- _connectionErrors.flush()
- _players.resetReplayCache()
- _messages.resetReplayCache()
- _chatMessages.resetReplayCache()
- _game.resetReplayCache()
- _hostInputAuthorityEnabled.resetReplayCache()
- _padBuffer.resetReplayCache()
- _saveTransferProgress.value = null
- }
-
- private fun createSessionScope(): CoroutineScope {
- sessionScope?.cancel()
- return CoroutineScope(SupervisorJob() + Dispatchers.IO).also {
- sessionScope = it
+ val currentNetPlayUICallbacksPointer = netPlayUICallbacksPointer
+ if (currentNetPlayUICallbacksPointer != 0L) {
+ netPlayUICallbacksPointer = 0
+ nativeReleaseUICallbacks(currentNetPlayUICallbacksPointer)
}
}
- @JvmStatic
- private external fun Join(): Long
+ // JNI methods
- @JvmStatic
- external fun isClientConnected(): Boolean
+ private external fun nativeCreateUICallbacks(): Long
- @JvmStatic
- external fun sendMessage(message: String)
+ private external fun nativeJoin(): Long
- @JvmStatic
- external fun adjustPadBufferSize(buffer: Int)
+ private external fun nativeSendMessage(message: String)
- @JvmStatic
- private external fun ReleaseBootSessionData()
+ private external fun nativeAdjustPadBufferSize(buffer: Int)
- @JvmStatic
- private external fun ReleaseNetplayClient()
+ private external fun nativeReleaseUICallbacks(pointer: Long)
- private fun mergeMessages(): Flow<NetplayMessage> = merge(
- chatMessages.map { NetplayMessage.Chat(it) },
- game.map { NetplayMessage.GameChanged(it) },
- hostInputAuthorityEnabled.map { NetplayMessage.HostInputAuthorityChanged(it) },
- padBuffer.map { NetplayMessage.BufferChanged(it) },
- )
+ private external fun nativeReleaseClient(pointer: Long)
+
+ private external fun nativeReleaseBootSessionData(pointer: Long)
// NetPlayUI callbacks
@Keep
- @JvmStatic
fun onBootGame(gameFilePath: String, bootSessionDataPointer: Long) {
this.bootSessionDataPointer = bootSessionDataPointer
_stopGame.flush()
@@ -191,57 +196,47 @@ object Netplay {
}
@Keep
- @JvmStatic
fun onStopGame() {
_stopGame.trySend(Unit)
}
@Keep
- @JvmStatic
fun onConnectionLost() {
_connectionLost.trySend(Unit)
}
@Keep
- @JvmStatic
fun onConnectionError(message: String) {
_connectionErrors.trySend(message)
}
@Keep
- @JvmStatic
fun onUpdate(players: Array<Player>) {
_players.tryEmit(players.toList())
}
@Keep
- @JvmStatic
fun onChatMessageReceived(message: String) {
_chatMessages.tryEmit(message)
}
@Keep
- @JvmStatic
fun onHostInputAuthorityChanged(enabled: Boolean) {
_hostInputAuthorityEnabled.tryEmit(enabled)
}
@Keep
- @JvmStatic
fun onGameChanged(game: String) {
_game.tryEmit(game)
}
@Keep
- @JvmStatic
fun onPadBufferChanged(buffer: Int) {
- // Only for remote pad buffer settings. Ignore local max buffer changes.
if (_hostInputAuthorityEnabled.replayCache.firstOrNull() == true) return
_padBuffer.tryEmit(buffer)
}
@Keep
- @JvmStatic
fun onShowChunkedProgressDialog(title: String, dataSize: Long, playerIds: IntArray) {
val players = _players.replayCache.firstOrNull()
_saveTransferProgress.value = SaveTransferProgress(
@@ -258,7 +253,6 @@ object Netplay {
}
@Keep
- @JvmStatic
fun onSetChunkedProgress(playerId: Int, progress: Long) {
val current = _saveTransferProgress.value
_saveTransferProgress.value = current?.copy(
@@ -273,11 +267,9 @@ object Netplay {
}
@Keep
- @JvmStatic
fun onHideChunkedProgressDialog() {
_saveTransferProgress.value = null
}
-
}
private fun <T> Channel<T>.flush() {
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/model/NetplaySetupViewModel.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/model/NetplaySetupViewModel.kt
index 2a04e41c35..a9b34d3147 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/model/NetplaySetupViewModel.kt
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/model/NetplaySetupViewModel.kt
@@ -3,22 +3,31 @@
package org.dolphinemu.dolphinemu.features.netplay.model
import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.asFlow
import androidx.lifecycle.viewModelScope
+import kotlinx.coroutines.Job
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.channels.Channel.Factory.CONFLATED
+import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.launch
-import org.dolphinemu.dolphinemu.features.netplay.Netplay
+import org.dolphinemu.dolphinemu.features.netplay.NetplayManager
import org.dolphinemu.dolphinemu.features.settings.model.IntSetting
import org.dolphinemu.dolphinemu.features.settings.model.NativeConfig
import org.dolphinemu.dolphinemu.features.settings.model.StringSetting
import org.dolphinemu.dolphinemu.services.GameFileCacheManager
-class NetplaySetupViewModel : ViewModel() {
+class NetplaySetupViewModel(
+ private val netplayManager: NetplayManager,
+) : ViewModel() {
+
private val _connectionRole = MutableStateFlow<ConnectionRole>(ConnectionRole.Connect)
val connectionRole = _connectionRole.asStateFlow()
@@ -45,7 +54,8 @@ class NetplaySetupViewModel : ViewModel() {
private val _connecting = MutableStateFlow(false)
val connecting = _connecting.asStateFlow()
- val errors = Netplay.connectionErrors
+ private val _errors = MutableSharedFlow<String>(extraBufferCapacity = 8)
+ val errors = _errors.asSharedFlow()
init {
GameFileCacheManager.startLoad()
@@ -89,16 +99,42 @@ class NetplaySetupViewModel : ViewModel() {
}
fun connect() {
+ if (_connecting.value) return
+
_connecting.value = true
viewModelScope.launch {
- GameFileCacheManager.isLoading().asFlow().first { it == false }
-
- if (Netplay.join()) {
- _showNetplayScreen.trySend(Unit)
+ var errorForwarding: Job? = null
+
+ try {
+ GameFileCacheManager.isLoading().asFlow().first { it == false }
+
+ val session = netplayManager.createSession()
+ errorForwarding = session.connectionErrors
+ .onEach { _errors.emit(it) }
+ .launchIn(this)
+
+ if (session.join()) {
+ _showNetplayScreen.trySend(Unit)
+ }
+ } finally {
+ errorForwarding?.cancel()
+ _connecting.value = false
}
+ }
+ }
+
+ override fun onCleared() {
+ super.onCleared()
+ // There should not be an active session at this point but in case one was created
+ // but launching the Netplay screen failed, close it.
+ netplayManager.activeSession?.closeBlocking()
+ }
- _connecting.value = false
+ class Factory(private val netplayManager: NetplayManager) : ViewModelProvider.Factory {
+ @Suppress("UNCHECKED_CAST")
+ override fun <T : ViewModel> create(modelClass: Class<T>): T {
+ return NetplaySetupViewModel(netplayManager) as T
}
}
}
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 66ad26aaec..96f9d7328b 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
@@ -3,51 +3,43 @@
package org.dolphinemu.dolphinemu.features.netplay.model
import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
-import kotlinx.coroutines.channels.Channel
-import kotlinx.coroutines.channels.Channel.Factory.CONFLATED
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.asStateFlow
-import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
-import org.dolphinemu.dolphinemu.features.netplay.Netplay
+import org.dolphinemu.dolphinemu.features.netplay.NetplaySession
import org.dolphinemu.dolphinemu.features.settings.model.IntSetting
import org.dolphinemu.dolphinemu.features.settings.model.NativeConfig
-class NetplayViewModel : ViewModel() {
- val launchGame = Netplay.launchGame
+class NetplayViewModel(
+ private val netplaySession: NetplaySession,
+) : ViewModel() {
- private val _goBack = Channel<Unit>(CONFLATED)
- val goBack = _goBack.receiveAsFlow()
+ val launchGame = netplaySession.launchGame
- val connectionLost = Netplay.connectionLost
+ val connectionLost = netplaySession.connectionLost
- val players = Netplay.players
+ val players = netplaySession.players
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), emptyList())
- val messages = Netplay.messages
+ val messages = netplaySession.messages
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), emptyList())
- val game = Netplay.game
+ val game = netplaySession.game
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), "")
- val hostInputAuthority = Netplay.hostInputAuthorityEnabled
+ val hostInputAuthority = netplaySession.hostInputAuthorityEnabled
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
private val _maxBuffer = MutableStateFlow(IntSetting.NETPLAY_CLIENT_BUFFER_SIZE.int)
val maxBuffer = _maxBuffer.asStateFlow()
- val saveTransferProgress = Netplay.saveTransferProgress
-
- init {
- if (!Netplay.isClientConnected()) {
- _goBack.trySend(Unit)
- }
- }
+ val saveTransferProgress = netplaySession.saveTransferProgress
fun sendMessage(message: String) {
val trimmedMessage = message.trim()
@@ -55,20 +47,29 @@ class NetplayViewModel : ViewModel() {
return
}
- Netplay.sendMessage(trimmedMessage)
+ netplaySession.sendMessage(trimmedMessage)
}
fun setMaxBuffer(buffer: Int) {
_maxBuffer.value = buffer
IntSetting.NETPLAY_CLIENT_BUFFER_SIZE.setInt(NativeConfig.LAYER_BASE, buffer)
- Netplay.adjustPadBufferSize(buffer)
+ netplaySession.adjustPadBufferSize(buffer)
}
@OptIn(DelicateCoroutinesApi::class)
override fun onCleared() {
super.onCleared()
+ // Closing the netplay session is a bit slow for the main thread so launch in
+ // GlobalScope and allow the activity and view model to finish immediately.
GlobalScope.launch {
- Netplay.quit()
+ netplaySession.close()
+ }
+ }
+
+ class Factory(private val session: NetplaySession) : ViewModelProvider.Factory {
+ @Suppress("UNCHECKED_CAST")
+ override fun <T : ViewModel> create(modelClass: Class<T>): T {
+ return NetplayViewModel(session) as T
}
}
}
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 8a8f860825..f2acf50107 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
@@ -16,6 +16,7 @@ import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import org.dolphinemu.dolphinemu.activities.EmulationActivity
+import org.dolphinemu.dolphinemu.features.netplay.NetplayManager
import org.dolphinemu.dolphinemu.features.netplay.model.NetplayViewModel
import org.dolphinemu.dolphinemu.ui.main.ThemeProvider
import org.dolphinemu.dolphinemu.ui.theme.DolphinTheme
@@ -29,11 +30,13 @@ class NetplayActivity : AppCompatActivity(), ThemeProvider {
enableEdgeToEdge()
super.onCreate(savedInstanceState)
- val viewModel = ViewModelProvider(this)[NetplayViewModel::class.java]
+ val session = NetplayManager.activeSession
+ if (session == null) {
+ finish()
+ return
+ }
- viewModel.goBack
- .onEach { finish() }
- .launchIn(lifecycleScope)
+ val viewModel = ViewModelProvider(this, NetplayViewModel.Factory(session))[NetplayViewModel::class.java]
viewModel.launchGame
.flowWithLifecycle(lifecycle, Lifecycle.State.STARTED)
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/ui/NetplaySetupActivity.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/ui/NetplaySetupActivity.kt
index 8058b3ad96..145cf7d635 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/ui/NetplaySetupActivity.kt
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/ui/NetplaySetupActivity.kt
@@ -15,6 +15,7 @@ import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
+import org.dolphinemu.dolphinemu.features.netplay.NetplayManager
import org.dolphinemu.dolphinemu.features.netplay.model.NetplaySetupViewModel
import org.dolphinemu.dolphinemu.ui.main.ThemeProvider
import org.dolphinemu.dolphinemu.ui.theme.DolphinTheme
@@ -28,7 +29,10 @@ class NetplaySetupActivity : AppCompatActivity(), ThemeProvider {
enableEdgeToEdge()
super.onCreate(savedInstanceState)
- val viewModel = ViewModelProvider(this)[NetplaySetupViewModel::class.java]
+ val viewModel = ViewModelProvider(
+ this,
+ NetplaySetupViewModel.Factory(NetplayManager)
+ )[NetplaySetupViewModel::class.java]
viewModel.showNetplayScreen
.flowWithLifecycle(lifecycle, Lifecycle.State.STARTED)
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.kt
index 49331d8a4c..c989cdc780 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.kt
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.kt
@@ -16,7 +16,7 @@ import kotlinx.coroutines.launch
import org.dolphinemu.dolphinemu.NativeLibrary
import org.dolphinemu.dolphinemu.activities.EmulationActivity
import org.dolphinemu.dolphinemu.databinding.FragmentEmulationBinding
-import org.dolphinemu.dolphinemu.features.netplay.Netplay
+import org.dolphinemu.dolphinemu.features.netplay.NetplayManager
import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting
import org.dolphinemu.dolphinemu.features.settings.model.Settings
import org.dolphinemu.dolphinemu.overlay.InputOverlay
@@ -211,7 +211,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
// Don't load temporary saves when launching Netplay, this path can trigger
// when a game starts due to orientation changes caused by a mismatch in menu
// vs emulation activity orientations.
- if (loadPreviousTemporaryState && !Netplay.isLaunching) {
+ val netplaySession = NetplayManager.activeSession
+ if (loadPreviousTemporaryState && netplaySession?.isLaunching != true) {
Log.debug("[EmulationFragment] Starting emulation thread from previous state.")
val paths = requireNotNull(gamePaths) {
"Cannot start emulation without any game paths"
@@ -221,16 +222,20 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
if (launchSystemMenu) {
Log.debug("[EmulationFragment] Starting emulation thread for the Wii Menu.")
NativeLibrary.RunSystemMenu()
- } else if (Netplay.isLaunching) {
+ } else if (netplaySession?.isLaunching == true) {
Log.debug("[EmulationFragment] Starting emulation thread for Netplay.")
val paths = requireNotNull(gamePaths) {
"Cannot start emulation without any game paths"
}
lifecycleScope.launch {
- Netplay.stopGame.first()
+ netplaySession.stopGame.first()
stopEmulation()
}
- NativeLibrary.RunNetPlay(paths, riivolution)
+ NativeLibrary.RunNetPlay(
+ paths,
+ riivolution,
+ netplaySession.consumeBootSessionData()
+ )
} else {
Log.debug("[EmulationFragment] Starting emulation thread.")
val paths = requireNotNull(gamePaths) {