-
-
Notifications
You must be signed in to change notification settings - Fork 404
feat: explicit progress [QoL] #1849
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -117,6 +117,7 @@ import app.gamenative.ui.component.QuickMenu | |
| import app.gamenative.ui.component.QuickMenuAction | ||
| import app.gamenative.ui.component.SteamInviteState | ||
| import app.gamenative.ui.component.parseBooleanExtra | ||
| import app.gamenative.utils.BootProgress | ||
| import app.gamenative.ui.component.parsePositiveFpsLimit | ||
| import app.gamenative.ui.data.PerformanceHudConfig | ||
| import app.gamenative.ui.data.PerformanceHudSize | ||
|
|
@@ -2150,6 +2151,7 @@ fun XServerScreen( | |
|
|
||
| setupExecutor.submit { | ||
| try { | ||
| BootProgress.start() | ||
| val containerManager = ContainerManager(context) | ||
| // Configure WinHandler with container's input API settings | ||
| val handler = getxServer().winHandler | ||
|
|
@@ -2231,6 +2233,7 @@ fun XServerScreen( | |
| Timber.i("Doing things once") | ||
| val envVars = EnvVars() | ||
|
|
||
| BootProgress.phase(BootProgress.Phase.WINE_FILES) | ||
| runBlocking { | ||
| setupWineSystemFiles( | ||
| context, | ||
|
|
@@ -2247,6 +2250,7 @@ fun XServerScreen( | |
| extractArm64ecInputDLLs(context, container) // REQUIRED: Uses updated xinput1_3 main.c from x86_64 build, prevents crashes with 3+ players, avoids need for input shim dlls. | ||
| extractx86_64InputDlls(context, container) | ||
|
|
||
| BootProgress.phase(BootProgress.Phase.GRAPHICS) | ||
| runBlocking { | ||
| extractGraphicsDriverFiles( | ||
| context, | ||
|
|
@@ -3684,6 +3688,7 @@ private fun setupXEnvironment( | |
| onGameLaunchError: ((String) -> Unit)? = null, | ||
| offline: Boolean = false | ||
| ): XEnvironment { | ||
| BootProgress.phase(BootProgress.Phase.ENVIRONMENT) | ||
| ProcessHelper.hardKillStaleWineProcesses() | ||
|
|
||
| val gameSource = ContainerUtils.extractGameSourceFromContainerId(appId) | ||
|
|
@@ -3877,9 +3882,9 @@ private fun setupXEnvironment( | |
| onError = onGameLaunchError | ||
| ) | ||
| if (preInstallCommands.isNotEmpty()) { | ||
| PluviaApp.events.emit(AndroidEvent.SetBootingSplashText("Installing prerequisites...")) | ||
| BootProgress.phase(BootProgress.Phase.PREREQS, "1/${preInstallCommands.size}") | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: When an intermediate Wine window maps during setup, Prompt for AI agents
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not sure that problem is exactly like you describe it, but i found one related and i'll fix it |
||
| } else { | ||
| PluviaApp.events.emit(AndroidEvent.SetBootingSplashText("Launching game...")) | ||
| BootProgress.phase(BootProgress.Phase.LAUNCH) | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -3976,9 +3981,10 @@ private fun setupXEnvironment( | |
| } | ||
| val nextRemaining = remaining.drop(1) | ||
| if (nextRemaining.isEmpty()) { | ||
| PluviaApp.events.emit(AndroidEvent.SetBootingSplashText("Launching game...")) | ||
| BootProgress.phase(BootProgress.Phase.LAUNCH) | ||
| } else { | ||
| PluviaApp.events.emit(AndroidEvent.SetBootingSplashText("Installing prerequisites...")) | ||
| val step = preInstallCommands.size - nextRemaining.size + 1 | ||
| BootProgress.phase(BootProgress.Phase.PREREQS, "$step/${preInstallCommands.size}") | ||
| } | ||
| chainPreInstallSteps(nextRemaining) | ||
| guestProgramLauncherComponent.start() | ||
|
|
@@ -4757,7 +4763,9 @@ private fun unpackExecutableFile( | |
| var output = StringBuilder() | ||
| if (needsUnpacking || containerVariantChanged){ | ||
| try { | ||
| PluviaApp.events.emit(AndroidEvent.SetBootingSplashText("Installing Mono...")) | ||
| BootProgress.phase(BootProgress.Phase.MONO) | ||
| // msiexec reports nothing back, so track the prefix directory it writes into instead. | ||
| BootProgress.watchOutput(File(imageFs.wineprefix, "drive_c/windows/mono")) | ||
| val monoCmd = "wine msiexec /i Z:\\opt\\mono-gecko-offline\\wine-mono-11.0.0-x86.msi && wineserver -k" | ||
| Timber.i("Install mono command $monoCmd") | ||
| val monoOutput = guestProgramLauncherComponent.execShellCommand(monoCmd) | ||
|
|
@@ -4787,7 +4795,7 @@ private fun unpackExecutableFile( | |
| val rootDir: File = imageFs.getRootDir() | ||
|
|
||
| try { | ||
| PluviaApp.events.emit(AndroidEvent.SetBootingSplashText("Handling DRM...")) | ||
| BootProgress.phase(BootProgress.Phase.DRM, "reading interfaces") | ||
| // a:/.../GameDir/orig_dll_path.txt (same dir as the EXE inside A:) | ||
| val origTxtFile = File("${imageFs.wineprefix}/dosdevices/a:/orig_dll_path.txt") | ||
|
|
||
|
|
@@ -4851,11 +4859,13 @@ private fun unpackExecutableFile( | |
| if (exePaths.isEmpty()) { | ||
| Timber.w("No executable path set, skipping Steamless") | ||
| } else { | ||
| PluviaApp.events.emit(AndroidEvent.SetBootingSplashText("Handling DRM...")) | ||
| BootProgress.phase(BootProgress.Phase.DRM) | ||
| for ((index, executablePath) in exePaths.withIndex()) { | ||
| if (exePaths.size > 1) { | ||
| PluviaApp.events.emit(AndroidEvent.SetBootingSplashText("Handling DRM (${index + 1}/${exePaths.size})")) | ||
| } | ||
| BootProgress.update( | ||
| index.toFloat() / exePaths.size, | ||
| "${index + 1}/${exePaths.size}: ${extractExecutableBasename(executablePath)}", | ||
| legacy = "Handling DRM (${index + 1}/${exePaths.size})".takeIf { exePaths.size > 1 }, | ||
| ) | ||
| var batchFile: File? = null | ||
| try { | ||
| // Normalize path: use forward slashes for Unix format, backslashes for Windows | ||
|
|
@@ -5061,7 +5071,7 @@ private suspend fun setupWineSystemFiles( | |
|
|
||
| // Download or use cached/bundled openal component | ||
| val openalFile = WinComponentDownloader.ensureWinComponentAvailable(context, "openal") { progress -> | ||
| Timber.d("Downloading openal component: ${(progress * 100).toInt()}%") | ||
| BootProgress.download("OpenAL", progress) | ||
| } | ||
|
|
||
| if (openalFile == null) { | ||
|
|
@@ -5195,7 +5205,7 @@ private suspend fun extractGraphicsDriverComponent( | |
| onExtractFileListener: OnExtractFileListener? = null | ||
| ) { | ||
| val componentFile = GraphicsDriverDownloader.ensureGraphicsDriverAvailable(context, componentId) { progress -> | ||
| Timber.d("Downloading graphics driver $componentId: ${(progress * 100).toInt()}%") | ||
| BootProgress.download("graphics driver $componentId", progress) | ||
| } | ||
|
|
||
| if (componentFile == null) { | ||
|
|
@@ -5231,7 +5241,7 @@ private suspend fun extractDXWrapperComponent( | |
| onExtractFileListener: OnExtractFileListener? | ||
| ) { | ||
| val componentFile = DXWrapperDownloader.ensureDXWrapperAvailable(context, componentId) { progress -> | ||
| Timber.d("Downloading dxwrapper $componentId: ${(progress * 100).toInt()}%") | ||
| BootProgress.download("dxwrapper $componentId", progress) | ||
| } | ||
|
|
||
| if (componentFile == null) { | ||
|
|
@@ -5468,7 +5478,7 @@ private suspend fun extractWinComponentFiles( | |
| val componentFile = WinComponentDownloader.ensureWinComponentAvailable( | ||
| context, identifier | ||
| ) { progress -> | ||
| Timber.d("Downloading wincomponent $identifier: ${(progress * 100).toInt()}%") | ||
| BootProgress.download("component $identifier", progress) | ||
| } | ||
|
|
||
| if (componentFile == null) { | ||
|
|
@@ -5626,7 +5636,7 @@ private suspend fun extractGraphicsDriverFiles( | |
|
|
||
| // Download or get cached core driver | ||
| val driverFile = CoreDriverDownloader.ensureCoreDriverAvailable(context, assetZip) { progress -> | ||
| Timber.d("Downloading core driver $assetZip: ${(progress * 100).toInt()}%") | ||
| BootProgress.download("core driver $assetZip", progress) | ||
| } | ||
|
|
||
| // Read manifest name from zip to determine folder name | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: When the other activity's
MainViewModelis cleared while an immersive launch is still booting, this global cleanup stops progress for the surviving activity. TieBootProgress.stop()to the activity that started the boot, or add ownership/reference tracking instead of stopping the singleton from every ViewModel.Prompt for AI agents