Games: launch options for Steam games in the Edit screen, shared with Steam's Properties (#1888)

This commit is contained in:
K11MCH1 authored and GitHub committed 2026-10-31 13:36:39 -04:00
1 parent ac132a23e2
commit 88719f25d2
37 files changed
+488 -4

No files matched your search

@@ -0,0 +1,162 @@
package com.droiddeck.launcher.frontend
import android.content.Context
import android.util.Log
import com.droiddeck.launcher.session.SessionPrefs
import com.droiddeck.launcher.session.SessionService
import com.droiddeck.launcher.session.SessionState
import com.droiddeck.launcher.stores.SteamLiveShortcuts
import java.io.File
import java.nio.file.Files
import java.nio.file.StandardCopyOption
object SteamLaunchOptions {
private const val TAG = "SteamLaunchOptions"
private val STEAM = listOf("UserLocalConfigStore", "Software", "Valve", "Steam")
fun current(context: Context, appId: Int): String =
SteamLiveShortcuts.launchOptions(context, appId.toLong()) ?: steam(SessionPrefs.activeSteamRoot(context), appId).orEmpty()
enum class Saved { YES, NO, DESKTOP }
fun set(context: Context, appId: Int, options: String, shown: String): Saved {
val value = options.trim()
if (SessionState.running && SessionState.mode == SessionService.MODE_DESKTOP) return Saved.DESKTOP
if (SessionState.running && SessionState.mode == SessionService.MODE_STEAM) {
val live = SteamLiveShortcuts.launchOptions(context, appId.toLong()) ?: return Saved.NO
if (live.trim() != shown.trim()) return Saved.NO
return if (SteamLiveShortcuts.setLaunchOptions(context, appId.toLong(), value)) Saved.YES else Saved.NO
}
val home = SessionPrefs.activeSteamRoot(context)
if (steam(home, appId).orEmpty().trim() != shown.trim()) return Saved.NO
return if (write(home, appId, value)) Saved.YES else Saved.NO
}
internal fun steam(steamHome: File, appId: Int): String? {
val config = AddedGames.accountConfig(steamHome) ?: return null
val text = runCatching { File(config, "localconfig.vdf").readText() }.getOrNull() ?: return null
return launchOptions(text, appId)
}
internal fun write(steamHome: File, appId: Int, options: String): Boolean {
val config = AddedGames.accountConfig(steamHome)?.let { File(it, "localconfig.vdf") } ?: return false
val text = runCatching { config.readText() }.getOrNull() ?: return false
val updated = withLaunchOptions(text, appId, options) ?: return false
if (updated == text) return true
val staged = File(config.parentFile, config.name + ".staged")
return try {
staged.writeText(updated)
if (config.readText() != text) {
staged.delete()
return false
}
Files.move(staged.toPath(), config.toPath(), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE)
true
} catch (e: Exception) {
staged.delete()
Log.w(TAG, "could not write launch options to ${config.path}", e)
false
}
}
internal fun launchOptions(text: String, appId: Int): String? {
val app = section(text, STEAM + "apps" + appId.toString()) ?: return null
return entries(text, app.valueStart, app.end).firstOrNull { !it.section && it.key.equals("LaunchOptions", true) }
?.let { unescape(text.substring(it.valueStart + 1, it.end)) }
}
internal fun withLaunchOptions(text: String, appId: Int, options: String): String? {
val newline = if (text.contains("\r\n")) "\r\n" else "\n"
var updated = text
var path = STEAM
for (key in listOf("apps", appId.toString())) {
updated = withSection(updated, section(updated, path) ?: return null, key, newline) ?: return null
path = path + key
}
val app = section(updated, path) ?: return null
val value = "\"" + escape(options) + "\""
entries(updated, app.valueStart, app.end).firstOrNull { !it.section && it.key.equals("LaunchOptions", true) }?.let {
return updated.replaceRange(it.valueStart, it.end + 1, value)
}
val lineStart = closingLine(updated, app) ?: return null
val indent = updated.substring(lineStart, app.end) + "\t"
return updated.substring(0, lineStart) + indent + "\"LaunchOptions\"\t\t" + value + newline + updated.substring(lineStart)
}
private class Entry(val key: String, val valueStart: Int, val end: Int, val section: Boolean)
private fun section(text: String, path: List<String>): Entry? {
var found: Entry? = null
for (key in path) {
found = entries(text, found?.valueStart ?: -1, found?.end ?: text.length)
.firstOrNull { it.section && it.key.equals(key, true) } ?: return null
}
return found
}
private fun entries(text: String, open: Int, close: Int): List<Entry> {
val found = ArrayList<Entry>()
var key: String? = null
var i = open + 1
while (i < close) {
when {
text[i] == '"' -> {
val end = stringEnd(text, i) ?: return found
if (key == null) key = unescape(text.substring(i + 1, end)) else { found += Entry(key, i, end, false); key = null }
i = end + 1
}
text[i] == '{' -> {
val end = sectionEnd(text, i) ?: return found
key?.let { found += Entry(it, i, end, true) }
key = null
i = end + 1
}
text.startsWith("//", i) -> i = text.indexOf('\n', i).let { if (it < 0) close else it }
else -> i++
}
}
return found
}
private fun stringEnd(text: String, open: Int): Int? {
var i = open + 1
while (i < text.length) {
when (text[i]) {
'\\' -> i += 2
'"' -> return i
else -> i++
}
}
return null
}
private fun sectionEnd(text: String, open: Int): Int? {
var depth = 0
var i = open
while (i < text.length) {
when (text[i]) {
'"' -> i = stringEnd(text, i) ?: return null
'{' -> depth++
'}' -> if (--depth == 0) return i
}
i++
}
return null
}
private fun withSection(text: String, parent: Entry, key: String, newline: String): String? {
if (entries(text, parent.valueStart, parent.end).any { it.section && it.key.equals(key, true) }) return text
val lineStart = closingLine(text, parent) ?: return null
val indent = text.substring(lineStart, parent.end) + "\t"
return text.substring(0, lineStart) + "$indent\"$key\"$newline$indent{$newline$indent}$newline" + text.substring(lineStart)
}
private fun closingLine(text: String, section: Entry): Int? {
val lineStart = text.lastIndexOf('\n', section.end - 1) + 1
return lineStart.takeIf { lineStart > section.valueStart && text.substring(lineStart, section.end).all { it == '\t' || it == ' ' } }
}
private fun escape(value: String) = value.replace("\\", "\\\\").replace("\"", "\\\"")
private fun unescape(value: String) = value.replace(Regex("\\\\(.)"), "$1")
}
@@ -92,6 +92,28 @@ object SteamLiveShortcuts {
if (evaluate(context, js) != null) Log.i(TAG, "live shortcuts: updated $id")
}
fun launchOptions(context: Context, appId: Long): String? {
if (!clientRunning()) return null
val js = """
new Promise(done => {
let handle = null, answer;
const finish = d => { clearTimeout(timer); try { handle?.unregister(); } catch (e) {} done(d); };
const timer = setTimeout(() => finish(null), 4000);
handle = SteamClient.Apps.RegisterForAppDetails(${appId and 0xFFFFFFFFL}, d => { answer = d; if (handle) finish(d); });
if (answer !== undefined) finish(answer);
}).then(d => typeof d?.strLaunchOptions === 'string' ? d.strLaunchOptions : null)
""".trimIndent()
return evaluate(context, js)
}
fun setLaunchOptions(context: Context, appId: Long, options: String): Boolean {
if (!clientRunning()) return false
val id = appId and 0xFFFFFFFFL
val done = evaluate(context, "(async () => { SteamClient.Apps.SetAppLaunchOptions($id, ${JSONObject.quote(options)}); return 1; })()") != null
if (done) Log.i(TAG, "live: launch options for $id")
return done
}
fun setArt(context: Context, appId: Long, assetType: Int?, file: java.io.File?, iconPath: String? = null) {
if (!clientRunning()) return
val id = appId and 0xFFFFFFFFL
@@ -68,6 +68,7 @@ import com.droiddeck.launcher.frontend.AddedGames
import com.droiddeck.launcher.frontend.LogoPosition
import com.droiddeck.launcher.frontend.SteamGameArt
import com.droiddeck.launcher.frontend.SteamGridDb
import com.droiddeck.launcher.frontend.SteamLaunchOptions
import com.droiddeck.launcher.session.SessionPrefs
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@@ -191,7 +192,7 @@ internal fun SteamGameArtEditor(
game: com.droiddeck.launcher.frontend.Library.SteamGame, onClose: () -> Unit, onChanged: () -> Unit,
) {
val target = remember(game.appId) { ArtTarget.of(game) }
ArtOnlyEditor(game.name, target, game, { SteamGameArt.describe(it, game) }, onClose, onChanged)
ArtOnlyEditor(game.name, target, game, { SteamGameArt.describe(it, game) }, onClose, onChanged, launchAppId = game.appId)
}
@Composable
@@ -207,18 +208,25 @@ internal fun StoreGameArtEditor(folder: String, name: String, onClose: () -> Uni
@Composable
private fun ArtOnlyEditor(
name: String, target: ArtTarget?, refresh: Any?, describe: (Context) -> List<AddedGameArt.SlotState>,
onClose: () -> Unit, onChanged: () -> Unit,
onClose: () -> Unit, onChanged: () -> Unit, launchAppId: Int? = null,
) {
val app = LocalContext.current.applicationContext
val colors = MaterialTheme.colorScheme
val scope = rememberCoroutineScope()
val shown = rememberShown(onClose)
val close = { shown.targetState = false }
var version by remember { mutableIntStateOf(0) }
var arts by remember { mutableStateOf<List<AddedGameArt.SlotState>>(emptyList()) }
var artSlot by remember { mutableStateOf<AddedGameArt.Slot?>(null) }
var logoOpen by remember { mutableStateOf(false) }
var launchOptions by remember { mutableStateOf<String?>(null) }
var launchVersion by remember { mutableIntStateOf(0) }
var editingLaunch by remember { mutableStateOf<String?>(null) }
var launchSaving by remember { mutableStateOf(false) }
var launchError by remember { mutableStateOf<Int?>(null) }
val position = rememberLogoPosition(target, version)
LaunchedEffect(version, refresh) { if (target != null) arts = withContext(Dispatchers.IO) { describe(app) } }
LaunchedEffect(launchAppId, launchVersion) { if (launchAppId != null) launchOptions = withContext(Dispatchers.IO) { SteamLaunchOptions.current(app, launchAppId) } }
val first = remember { FocusRequester() }
LaunchedEffect(Unit) { focusWithinFrames({ false }) { first } }
AppDialog(shown, close, "artEditor", wide = false, maxWidth = 460.dp) {
@@ -228,10 +236,19 @@ private fun ArtOnlyEditor(
verticalArrangement = Arrangement.spacedBy(6.dp),
modifier = Modifier.fillMaxWidth().heightIn(max = maxHeight).verticalScroll(rememberScrollState()),
) {
Text(stringResource(R.string.edit_artwork), fontSize = 12.sp, color = colors.onSurfaceVariant, modifier = Modifier.padding(start = 4.dp, top = 2.dp))
if (launchAppId != null) {
FieldRow(stringResource(R.string.edit_launch_options), focus = first, onClick = { if (!launchSaving) launchOptions?.let { editingLaunch = it } }) {
val options = launchOptions
if (options == null || launchSaving) Loading() else ValueText(options.ifEmpty { "—" }, muted = options.isEmpty())
}
val error = launchError
if (error != null) Text(stringResource(error), fontSize = 12.sp, color = colors.error, modifier = Modifier.padding(start = 4.dp))
else Text(stringResource(R.string.edit_launch_options_steam_hint), fontSize = 12.sp, color = colors.onSurfaceVariant, modifier = Modifier.padding(start = 4.dp))
}
Text(stringResource(R.string.edit_artwork), fontSize = 12.sp, color = colors.onSurfaceVariant, modifier = Modifier.padding(start = 4.dp, top = if (launchAppId != null) 8.dp else 2.dp))
for (slot in AddedGameArt.Slot.values()) key(slot) {
val state = arts.firstOrNull { it.slot == slot }
FieldRow(slot.label(), focus = if (slot == AddedGameArt.Slot.COVER) first else null, onClick = { if (target != null) artSlot = slot }) {
FieldRow(slot.label(), focus = if (slot == AddedGameArt.Slot.COVER && launchAppId == null) first else null, onClick = { if (target != null) artSlot = slot }) {
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(10.dp)) {
SlotThumb(slot, state?.file)
if (state != null) ValueText(artSourceLabel(state.source), muted = true) else Loading()
@@ -241,6 +258,27 @@ private fun ArtOnlyEditor(
PickerRow(Icons.Outlined.Tune, stringResource(R.string.art_adjust_logo), logoPositionSummary(position?.value), enabled = target != null && position != null) { logoOpen = true }
}
}
val before = editingLaunch
if (before != null && launchAppId != null) TextEntryDialog(stringResource(R.string.edit_launch_options), before, onDismiss = { editingLaunch = null }) { value ->
if (launchSaving || value == before.trim()) return@TextEntryDialog
launchSaving = true
scope.launch {
try {
val saved = withContext(Dispatchers.IO) { SteamLaunchOptions.set(app, launchAppId, value, before) }
launchError = when (saved) {
SteamLaunchOptions.Saved.YES -> null
SteamLaunchOptions.Saved.DESKTOP -> R.string.edit_launch_options_desktop
SteamLaunchOptions.Saved.NO -> R.string.edit_launch_options_not_saved
}
if (saved == SteamLaunchOptions.Saved.YES) launchOptions = value else {
launchOptions = null
launchVersion++
}
} finally {
launchSaving = false
}
}
}
val chosen = target ?: return
artSlot?.let { slot ->
ArtChooserDialog(chosen, slot, arts.firstOrNull { it.slot == slot }, onBack = { artSlot = null }, onCloseAll = { artSlot = null; close() }) { version++; onChanged() }
+3
View File
@@ -2473,6 +2473,9 @@
<string name="edit_target">الهدف</string>
<string name="edit_start_in">بدء التشغيل في</string>
<string name="edit_launch_options">خيارات التشغيل</string>
<string name="edit_launch_options_steam_hint">مشتركة مع خصائص Steam: أي تغيير في أحدهما يظهر في كليهما.</string>
<string name="edit_launch_options_not_saved">تعذّر حفظ خيارات التشغيل في Steam. حاول مرة أخرى.</string>
<string name="edit_launch_options_desktop">قد يكون Steam مفتوحًا في جلسة سطح المكتب. غيّر خيارات التشغيل من خصائصه، أو أغلق الجلسة أولًا.</string>
<string name="edit_artwork">الصور الفنية</string>
<string name="edit_other_exe">ملف exe آخر…</string>
<string name="edit_remove">إزالة</string>
@@ -2422,6 +2422,9 @@
<string name="edit_target">Destino</string>
<string name="edit_start_in">Iniciar en</string>
<string name="edit_launch_options">Opciones de lanzamiento</string>
<string name="edit_launch_options_steam_hint">Se comparten con las Propiedades de Steam: un cambio en cualquiera de los dos se ve en ambos.</string>
<string name="edit_launch_options_not_saved">No se pudieron guardar las opciones de lanzamiento en Steam. Inténtalo de nuevo.</string>
<string name="edit_launch_options_desktop">Es posible que Steam esté abierto en la sesión de escritorio. Cambia las opciones de lanzamiento en sus Propiedades o cierra primero la sesión.</string>
<string name="edit_artwork">Ilustraciones</string>
<string name="edit_other_exe">Otro exe…</string>
<string name="edit_remove">Quitar</string>
+3
View File
@@ -2381,6 +2381,9 @@
<string name="edit_target">Цел</string>
<string name="edit_start_in">Старт в</string>
<string name="edit_launch_options">Настройки за стартиране</string>
<string name="edit_launch_options_steam_hint">Общи са със „Свойства“ в Steam: промяна на едното място се вижда и на двете.</string>
<string name="edit_launch_options_not_saved">Настройките за стартиране не можаха да бъдат запазени в Steam. Опитайте отново.</string>
<string name="edit_launch_options_desktop">Steam може да е отворен в сесията на работния плот. Променете настройките за стартиране в неговите „Свойства“ или първо затворете сесията.</string>
<string name="edit_artwork">Визия</string>
<string name="edit_other_exe">Друг exe…</string>
<string name="edit_remove">Премахни</string>
+3
View File
@@ -2427,6 +2427,9 @@
<string name="edit_target">Cíl</string>
<string name="edit_start_in">Spustit v</string>
<string name="edit_launch_options">Možnosti spuštění</string>
<string name="edit_launch_options_steam_hint">Sdíleno s Vlastnostmi ve Steamu: změna na jednom místě se projeví na obou.</string>
<string name="edit_launch_options_not_saved">Možnosti spuštění se nepodařilo uložit do Steamu. Zkuste to znovu.</string>
<string name="edit_launch_options_desktop">Steam může být otevřený v relaci Plochy. Změňte možnosti spuštění v jeho Vlastnostech, nebo nejdřív relaci ukončete.</string>
<string name="edit_artwork">Grafika</string>
<string name="edit_other_exe">Jiný exe…</string>
<string name="edit_remove">Odstranit</string>
+3
View File
@@ -2381,6 +2381,9 @@
<string name="edit_target">Mål</string>
<string name="edit_start_in">Start i</string>
<string name="edit_launch_options">Startindstillinger</string>
<string name="edit_launch_options_steam_hint">Delt med Egenskaber i Steam: en ændring det ene sted vises begge steder.</string>
<string name="edit_launch_options_not_saved">Startindstillingerne kunne ikke gemmes i Steam. Prøv igen.</string>
<string name="edit_launch_options_desktop">Steam kan være åben i skrivebordssessionen. Skift startindstillingerne under dens Egenskaber, eller luk sessionen først.</string>
<string name="edit_artwork">Grafik</string>
<string name="edit_other_exe">Anden exe…</string>
<string name="edit_remove">Fjern</string>
+3
View File
@@ -2370,6 +2370,9 @@
<string name="edit_target">Ziel</string>
<string name="edit_start_in">Ausführen in</string>
<string name="edit_launch_options">Startoptionen</string>
<string name="edit_launch_options_steam_hint">Gemeinsam mit den Eigenschaften in Steam: Eine Änderung an einer Stelle gilt für beide.</string>
<string name="edit_launch_options_not_saved">Die Startoptionen konnten nicht in Steam gespeichert werden. Versuche es erneut.</string>
<string name="edit_launch_options_desktop">Steam ist eventuell in der Desktop-Sitzung geöffnet. Ändere die Startoptionen dort in den Eigenschaften oder beende zuerst die Sitzung.</string>
<string name="edit_artwork">Grafiken</string>
<string name="edit_other_exe">Andere EXE…</string>
<string name="edit_remove">Entfernen</string>
+3
View File
@@ -2381,6 +2381,9 @@
<string name="edit_target">Προορισμός</string>
<string name="edit_start_in">Εκκίνηση σε</string>
<string name="edit_launch_options">Επιλογές εκκίνησης</string>
<string name="edit_launch_options_steam_hint">Κοινές με τις Ιδιότητες του Steam: μια αλλαγή στο ένα σημείο εμφανίζεται και στα δύο.</string>
<string name="edit_launch_options_not_saved">Δεν ήταν δυνατή η αποθήκευση των επιλογών εκκίνησης στο Steam. Δοκιμάστε ξανά.</string>
<string name="edit_launch_options_desktop">Το Steam μπορεί να είναι ανοιχτό στη συνεδρία επιφάνειας εργασίας. Αλλάξτε τις επιλογές εκκίνησης από τις Ιδιότητές του ή κλείστε πρώτα τη συνεδρία.</string>
<string name="edit_artwork">Γραφικά</string>
<string name="edit_other_exe">Άλλο exe…</string>
<string name="edit_remove">Κατάργηση</string>
+3
View File
@@ -2401,6 +2401,9 @@
<string name="edit_target">Destino</string>
<string name="edit_start_in">Iniciar en</string>
<string name="edit_launch_options">Opciones de lanzamiento</string>
<string name="edit_launch_options_steam_hint">Se comparten con las Propiedades de Steam: un cambio en cualquiera de los dos se ve en ambos.</string>
<string name="edit_launch_options_not_saved">No se pudieron guardar las opciones de lanzamiento en Steam. Inténtalo de nuevo.</string>
<string name="edit_launch_options_desktop">Puede que Steam esté abierto en la sesión de escritorio. Cambia las opciones de lanzamiento en sus Propiedades o cierra antes la sesión.</string>
<string name="edit_artwork">Ilustraciones</string>
<string name="edit_other_exe">Otro exe…</string>
<string name="edit_remove">Quitar</string>
+3
View File
@@ -2381,6 +2381,9 @@
<string name="edit_target">Kohde</string>
<string name="edit_start_in">Käynnistyskansio</string>
<string name="edit_launch_options">Käynnistysasetukset</string>
<string name="edit_launch_options_steam_hint">Jaettu Steamin Ominaisuuksien kanssa: muutos jommassakummassa näkyy molemmissa.</string>
<string name="edit_launch_options_not_saved">Käynnistysasetuksia ei voitu tallentaa Steamiin. Yritä uudelleen.</string>
<string name="edit_launch_options_desktop">Steam voi olla auki työpöytäistunnossa. Muuta käynnistysasetuksia sen Ominaisuuksista tai sulje istunto ensin.</string>
<string name="edit_artwork">Kuvitus</string>
<string name="edit_other_exe">Toinen exe…</string>
<string name="edit_remove">Poista</string>
+3
View File
@@ -2401,6 +2401,9 @@
<string name="edit_target">Cible</string>
<string name="edit_start_in">Démarrer dans</string>
<string name="edit_launch_options">Options de lancement</string>
<string name="edit_launch_options_steam_hint">Partagées avec les Propriétés de Steam : une modification d’un côté apparaît des deux.</string>
<string name="edit_launch_options_not_saved">Impossible d’enregistrer les options de lancement dans Steam. Réessayez.</string>
<string name="edit_launch_options_desktop">Steam est peut-être ouvert dans la session Bureau. Modifiez les options de lancement dans ses Propriétés, ou fermez d’abord la session.</string>
<string name="edit_artwork">Illustrations</string>
<string name="edit_other_exe">Autre exe…</string>
<string name="edit_remove">Retirer</string>
+3
View File
@@ -2381,6 +2381,9 @@
<string name="edit_target">टार्गेट</string>
<string name="edit_start_in">यहां शुरू करें</string>
<string name="edit_launch_options">लॉन्च विकल्प</string>
<string name="edit_launch_options_steam_hint">Steam की Properties के साथ साझा: किसी एक जगह किया गया बदलाव दोनों में दिखता है।</string>
<string name="edit_launch_options_not_saved">लॉन्च विकल्प Steam में सहेजे नहीं जा सके। फिर से कोशिश करें।</string>
<string name="edit_launch_options_desktop">Steam डेस्कटॉप सेशन में खुला हो सकता है। लॉन्च विकल्प उसकी Properties में बदलें, या पहले सेशन बंद करें।</string>
<string name="edit_artwork">आर्टवर्क</string>
<string name="edit_other_exe">दूसरा exe…</string>
<string name="edit_remove">हटाएं</string>
+3
View File
@@ -2381,6 +2381,9 @@
<string name="edit_target">Cél</string>
<string name="edit_start_in">Indítás innen</string>
<string name="edit_launch_options">Indítási beállítások</string>
<string name="edit_launch_options_steam_hint">Közös a Steam Tulajdonságaival: az egyik helyen végzett módosítás mindkettőben megjelenik.</string>
<string name="edit_launch_options_not_saved">Az indítási beállításokat nem sikerült menteni a Steambe. Próbáld újra.</string>
<string name="edit_launch_options_desktop">Lehet, hogy a Steam nyitva van az asztali munkamenetben. Módosítsd az indítási beállításokat a Tulajdonságaiban, vagy előbb zárd be a munkamenetet.</string>
<string name="edit_artwork">Illusztráció</string>
<string name="edit_other_exe">Másik exe…</string>
<string name="edit_remove">Eltávolítás</string>
+3
View File
@@ -2358,6 +2358,9 @@
<string name="edit_target">Target</string>
<string name="edit_start_in">Mulai di</string>
<string name="edit_launch_options">Opsi peluncuran</string>
<string name="edit_launch_options_steam_hint">Dibagikan dengan Properti Steam: perubahan di salah satunya muncul di keduanya.</string>
<string name="edit_launch_options_not_saved">Tidak dapat menyimpan opsi peluncuran ke Steam. Coba lagi.</string>
<string name="edit_launch_options_desktop">Steam mungkin terbuka di sesi desktop. Ubah opsi peluncuran di Properti Steam, atau tutup sesinya terlebih dahulu.</string>
<string name="edit_artwork">Artwork</string>
<string name="edit_other_exe">Exe lain…</string>
<string name="edit_remove">Hapus</string>
+3
View File
@@ -2393,6 +2393,9 @@
<string name="edit_target">Destinazione</string>
<string name="edit_start_in">Avvia in</string>
<string name="edit_launch_options">Opzioni di avvio</string>
<string name="edit_launch_options_steam_hint">Condivise con le Proprietà di Steam: una modifica in uno dei due punti compare in entrambi.</string>
<string name="edit_launch_options_not_saved">Impossibile salvare le opzioni di avvio in Steam. Riprova.</string>
<string name="edit_launch_options_desktop">Steam potrebbe essere aperto nella sessione desktop. Cambia le opzioni di avvio nelle sue Proprietà o chiudi prima la sessione.</string>
<string name="edit_artwork">Illustrazioni</string>
<string name="edit_other_exe">Altro exe…</string>
<string name="edit_remove">Rimuovi</string>
+3
View File
@@ -2325,6 +2325,9 @@
<string name="edit_target">ターゲット</string>
<string name="edit_start_in">開始フォルダ</string>
<string name="edit_launch_options">起動オプション</string>
<string name="edit_launch_options_steam_hint">Steam のプロパティと共通です。どちらかで変更すると両方に反映されます。</string>
<string name="edit_launch_options_not_saved">起動オプションを Steam に保存できませんでした。もう一度お試しください。</string>
<string name="edit_launch_options_desktop">デスクトップのセッションで Steam が開いている可能性があります。Steam のプロパティで起動オプションを変更するか、先にセッションを終了してください。</string>
<string name="edit_artwork">アートワーク</string>
<string name="edit_other_exe">別の exe…</string>
<string name="edit_remove">削除</string>
+3
View File
@@ -2358,6 +2358,9 @@
<string name="edit_target">대상</string>
<string name="edit_start_in">시작 위치</string>
<string name="edit_launch_options">실행 옵션</string>
<string name="edit_launch_options_steam_hint">Steam 속성과 공유됩니다. 어느 한쪽에서 바꾸면 양쪽에 모두 반영됩니다.</string>
<string name="edit_launch_options_not_saved">실행 옵션을 Steam에 저장하지 못했습니다. 다시 시도하세요.</string>
<string name="edit_launch_options_desktop">데스크톱 세션에서 Steam이 열려 있을 수 있습니다. Steam 속성에서 실행 옵션을 바꾸거나 먼저 세션을 닫으세요.</string>
<string name="edit_artwork">아트워크</string>
<string name="edit_other_exe">다른 exe…</string>
<string name="edit_remove">제거</string>
+3
View File
@@ -2358,6 +2358,9 @@
<string name="edit_target">Sasaran</string>
<string name="edit_start_in">Mula dalam</string>
<string name="edit_launch_options">Pilihan pelancaran</string>
<string name="edit_launch_options_steam_hint">Dikongsi dengan Properties dalam Steam: perubahan di salah satu tempat dipaparkan di kedua-duanya.</string>
<string name="edit_launch_options_not_saved">Tidak dapat menyimpan pilihan pelancaran ke Steam. Cuba lagi.</string>
<string name="edit_launch_options_desktop">Steam mungkin terbuka dalam sesi desktop. Tukar pilihan pelancaran dalam Properties Steam, atau tutup sesi itu dahulu.</string>
<string name="edit_artwork">Seni</string>
<string name="edit_other_exe">Exe lain…</string>
<string name="edit_remove">Alih keluar</string>
+3
View File
@@ -2381,6 +2381,9 @@
<string name="edit_target">Mål</string>
<string name="edit_start_in">Start i</string>
<string name="edit_launch_options">Startalternativer</string>
<string name="edit_launch_options_steam_hint">Delt med Egenskaper i Steam: en endring det ene stedet vises begge steder.</string>
<string name="edit_launch_options_not_saved">Kunne ikke lagre startalternativene i Steam. Prøv igjen.</string>
<string name="edit_launch_options_desktop">Steam kan være åpent i skrivebordssesjonen. Endre startalternativene under Egenskaper der, eller lukk sesjonen først.</string>
<string name="edit_artwork">Grafikk</string>
<string name="edit_other_exe">Annen exe…</string>
<string name="edit_remove">Fjern</string>
+3
View File
@@ -2381,6 +2381,9 @@
<string name="edit_target">Doel</string>
<string name="edit_start_in">Beginnen in</string>
<string name="edit_launch_options">Opstartopties</string>
<string name="edit_launch_options_steam_hint">Gedeeld met de Eigenschappen in Steam: een wijziging op de ene plek is op beide te zien.</string>
<string name="edit_launch_options_not_saved">De opstartopties konden niet in Steam worden opgeslagen. Probeer het opnieuw.</string>
<string name="edit_launch_options_desktop">Steam is misschien geopend in de desktopsessie. Wijzig de opstartopties daar in de Eigenschappen, of sluit eerst de sessie.</string>
<string name="edit_artwork">Artwork</string>
<string name="edit_other_exe">Andere exe…</string>
<string name="edit_remove">Verwijderen</string>
+3
View File
@@ -2427,6 +2427,9 @@
<string name="edit_target">Element docelowy</string>
<string name="edit_start_in">Uruchom w</string>
<string name="edit_launch_options">Opcje uruchamiania</string>
<string name="edit_launch_options_steam_hint">Wspólne z Właściwościami w Steam: zmiana w jednym miejscu jest widoczna w obu.</string>
<string name="edit_launch_options_not_saved">Nie udało się zapisać opcji uruchamiania w Steam. Spróbuj ponownie.</string>
<string name="edit_launch_options_desktop">Steam może być otwarty w sesji pulpitu. Zmień opcje uruchamiania w jego Właściwościach albo najpierw zamknij sesję.</string>
<string name="edit_artwork">Grafika</string>
<string name="edit_other_exe">Inny plik exe…</string>
<string name="edit_remove">Usuń</string>
@@ -2393,6 +2393,9 @@
<string name="edit_target">Destino</string>
<string name="edit_start_in">Iniciar em</string>
<string name="edit_launch_options">Opções de arranque</string>
<string name="edit_launch_options_steam_hint">Partilhadas com as Propriedades do Steam: uma alteração num dos locais aparece em ambos.</string>
<string name="edit_launch_options_not_saved">Não foi possível guardar as opções de arranque no Steam. Tenta novamente.</string>
<string name="edit_launch_options_desktop">O Steam pode estar aberto na sessão do ambiente de trabalho. Altera as opções de arranque nas Propriedades dele, ou fecha primeiro a sessão.</string>
<string name="edit_artwork">Imagens</string>
<string name="edit_other_exe">Outro exe…</string>
<string name="edit_remove">Remover</string>
+3
View File
@@ -2393,6 +2393,9 @@
<string name="edit_target">Destino</string>
<string name="edit_start_in">Iniciar em</string>
<string name="edit_launch_options">Opções de inicialização</string>
<string name="edit_launch_options_steam_hint">Compartilhadas com as Propriedades da Steam: uma alteração em um dos lugares aparece nos dois.</string>
<string name="edit_launch_options_not_saved">Não foi possível salvar as opções de inicialização na Steam. Tente novamente.</string>
<string name="edit_launch_options_desktop">A Steam pode estar aberta na sessão da área de trabalho. Altere as opções de inicialização nas Propriedades dela ou feche a sessão primeiro.</string>
<string name="edit_artwork">Artes</string>
<string name="edit_other_exe">Outro exe…</string>
<string name="edit_remove">Remover</string>
+3
View File
@@ -2404,6 +2404,9 @@
<string name="edit_target">Țintă</string>
<string name="edit_start_in">Pornește în</string>
<string name="edit_launch_options">Opțiuni de lansare</string>
<string name="edit_launch_options_steam_hint">Comune cu Proprietățile din Steam: o modificare într-unul dintre locuri apare în ambele.</string>
<string name="edit_launch_options_not_saved">Opțiunile de lansare nu au putut fi salvate în Steam. Încearcă din nou.</string>
<string name="edit_launch_options_desktop">Steam poate fi deschis în sesiunea desktop. Schimbă opțiunile de lansare din Proprietățile lui sau închide mai întâi sesiunea.</string>
<string name="edit_artwork">Grafică</string>
<string name="edit_other_exe">Alt exe…</string>
<string name="edit_remove">Elimină</string>
+3
View File
@@ -2424,6 +2424,9 @@
<string name="edit_target">Объект</string>
<string name="edit_start_in">Рабочая папка</string>
<string name="edit_launch_options">Параметры запуска</string>
<string name="edit_launch_options_steam_hint">Общие со «Свойствами» Steam: изменение в одном месте видно в обоих.</string>
<string name="edit_launch_options_not_saved">Не удалось сохранить параметры запуска в Steam. Попробуйте ещё раз.</string>
<string name="edit_launch_options_desktop">Steam может быть открыт в сессии рабочего стола. Измените параметры запуска в его «Свойствах» или сначала закройте сессию.</string>
<string name="edit_artwork">Обложки</string>
<string name="edit_other_exe">Другой exe…</string>
<string name="edit_remove">Убрать</string>
+3
View File
@@ -2381,6 +2381,9 @@
<string name="edit_target">Mål</string>
<string name="edit_start_in">Starta i</string>
<string name="edit_launch_options">Startalternativ</string>
<string name="edit_launch_options_steam_hint">Delas med Egenskaper i Steam: en ändring på det ena stället syns på båda.</string>
<string name="edit_launch_options_not_saved">Det gick inte att spara startalternativen i Steam. Försök igen.</string>
<string name="edit_launch_options_desktop">Steam kan vara öppet i skrivbordssessionen. Ändra startalternativen under Egenskaper där, eller stäng sessionen först.</string>
<string name="edit_artwork">Bildmaterial</string>
<string name="edit_other_exe">Annan exe…</string>
<string name="edit_remove">Ta bort</string>
+3
View File
@@ -2358,6 +2358,9 @@
<string name="edit_target">เป้าหมาย</string>
<string name="edit_start_in">เริ่มที่</string>
<string name="edit_launch_options">ตัวเลือกการเปิด</string>
<string name="edit_launch_options_steam_hint">ใช้ร่วมกับคุณสมบัติใน Steam: เปลี่ยนที่ใดที่หนึ่งก็จะแสดงในทั้งสองที่</string>
<string name="edit_launch_options_not_saved">บันทึกตัวเลือกการเปิดลงใน Steam ไม่ได้ ลองอีกครั้ง</string>
<string name="edit_launch_options_desktop">Steam อาจเปิดอยู่ในเซสชันเดสก์ท็อป เปลี่ยนตัวเลือกการเปิดในคุณสมบัติของ Steam หรือปิดเซสชันก่อน</string>
<string name="edit_artwork">ภาพปก</string>
<string name="edit_other_exe">exe อื่น…</string>
<string name="edit_remove">ลบ</string>
+3
View File
@@ -2370,6 +2370,9 @@
<string name="edit_target">Hedef</string>
<string name="edit_start_in">Başlangıç yeri</string>
<string name="edit_launch_options">Başlatma seçenekleri</string>
<string name="edit_launch_options_steam_hint">Steam Özellikleri ile ortaktır: birinde yapılan değişiklik ikisinde de görünür.</string>
<string name="edit_launch_options_not_saved">Başlatma seçenekleri Steam\'e kaydedilemedi. Tekrar deneyin.</string>
<string name="edit_launch_options_desktop">Steam masaüstü oturumunda açık olabilir. Başlatma seçeneklerini Steam Özellikleri\'nden değiştirin veya önce oturumu kapatın.</string>
<string name="edit_artwork">Görsel</string>
<string name="edit_other_exe">Diğer exe…</string>
<string name="edit_remove">Kaldır</string>
+3
View File
@@ -2427,6 +2427,9 @@
<string name="edit_target">Ціль</string>
<string name="edit_start_in">Робоча папка</string>
<string name="edit_launch_options">Параметри запуску</string>
<string name="edit_launch_options_steam_hint">Спільні з «Властивостями» Steam: зміна в одному місці видна в обох.</string>
<string name="edit_launch_options_not_saved">Не вдалося зберегти параметри запуску в Steam. Спробуйте ще раз.</string>
<string name="edit_launch_options_desktop">Steam може бути відкритий у сеансі робочого столу. Змініть параметри запуску в його «Властивостях» або спершу закрийте сеанс.</string>
<string name="edit_artwork">Графіка</string>
<string name="edit_other_exe">Інший exe…</string>
<string name="edit_remove">Вилучити</string>
+3
View File
@@ -2358,6 +2358,9 @@
<string name="edit_target">Đích</string>
<string name="edit_start_in">Khởi chạy trong</string>
<string name="edit_launch_options">Tùy chọn khởi chạy</string>
<string name="edit_launch_options_steam_hint">Dùng chung với Thuộc tính của Steam: thay đổi ở một nơi sẽ hiện ở cả hai.</string>
<string name="edit_launch_options_not_saved">Không thể lưu tùy chọn khởi chạy vào Steam. Hãy thử lại.</string>
<string name="edit_launch_options_desktop">Steam có thể đang mở trong phiên desktop. Hãy đổi tùy chọn khởi chạy trong Thuộc tính của Steam, hoặc đóng phiên trước.</string>
<string name="edit_artwork">Hình ảnh</string>
<string name="edit_other_exe">Exe khác…</string>
<string name="edit_remove">Xóa</string>
@@ -2400,6 +2400,9 @@
<string name="edit_target">目标</string>
<string name="edit_start_in">起始位置</string>
<string name="edit_launch_options">启动选项</string>
<string name="edit_launch_options_steam_hint">与 Steam 的“属性”共用:在任一处更改,两处都会更新。</string>
<string name="edit_launch_options_not_saved">无法将启动选项保存到 Steam。请重试。</string>
<string name="edit_launch_options_desktop">Steam 可能正在桌面会话中运行。请在 Steam 的“属性”中更改启动选项,或先关闭该会话。</string>
<string name="edit_artwork">美术图</string>
<string name="edit_other_exe">其他 exe…</string>
<string name="edit_remove">移除</string>
@@ -2326,6 +2326,9 @@
<string name="edit_target">目標</string>
<string name="edit_start_in">開始位置</string>
<string name="edit_launch_options">啟動選項</string>
<string name="edit_launch_options_steam_hint">與 Steam 的「內容」共用:在任一處更改,兩處都會更新。</string>
<string name="edit_launch_options_not_saved">無法將啟動選項儲存到 Steam。請再試一次。</string>
<string name="edit_launch_options_desktop">Steam 可能正在桌面會話中執行。請在 Steam 的「內容」中更改啟動選項,或先關閉該會話。</string>
<string name="edit_artwork">圖片</string>
<string name="edit_other_exe">其他 exe…</string>
<string name="edit_remove">移除</string>
@@ -2326,6 +2326,9 @@
<string name="edit_target">目標</string>
<string name="edit_start_in">開始位置</string>
<string name="edit_launch_options">啟動選項</string>
<string name="edit_launch_options_steam_hint">與 Steam 的「內容」共用:在任一處變更,兩處都會更新。</string>
<string name="edit_launch_options_not_saved">無法將啟動選項儲存至 Steam。請再試一次。</string>
<string name="edit_launch_options_desktop">Steam 可能正在桌面工作階段中執行。請在 Steam 的「內容」中變更啟動選項,或先關閉該工作階段。</string>
<string name="edit_artwork">圖片</string>
<string name="edit_other_exe">其他 exe…</string>
<string name="edit_remove">移除</string>
+3
View File
@@ -2508,6 +2508,9 @@
<string name="edit_target">Target</string>
<string name="edit_start_in">Start in</string>
<string name="edit_launch_options">Launch options</string>
<string name="edit_launch_options_steam_hint">Shared with Steam\'s Properties: a change in either one shows in both.</string>
<string name="edit_launch_options_not_saved">Could not save the launch options to Steam. Try again.</string>
<string name="edit_launch_options_desktop">Steam may be open in the desktop session. Change the launch options in its Properties, or close the session first.</string>
<string name="edit_artwork">Artwork</string>
<string name="edit_other_exe">Other exe…</string>
<string name="edit_remove">Remove</string>
@@ -0,0 +1,163 @@
package com.droiddeck.launcher.frontend
import com.droiddeck.launcher.session.SessionPrefs
import com.droiddeck.launcher.session.SessionService
import com.droiddeck.launcher.session.SessionState
import java.io.File
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.RuntimeEnvironment
import org.robolectric.annotation.Config
@RunWith(RobolectricTestRunner::class)
@Config(sdk = [33])
class SteamLaunchOptionsTest {
@get:Rule val tmp = TemporaryFolder()
private fun config(apps: String) = listOf(
"\"UserLocalConfigStore\"", "{", "\t\"Software\"", "\t{", "\t\t\"Valve\"", "\t\t{", "\t\t\t\"Steam\"", "\t\t\t{",
apps, "\t\t\t}", "\t\t}", "\t}", "\t\"WebStorage\"", "\t{", "\t\t\"x\"\t\t\"1\"", "\t}", "}", "",
).joinToString("\n")
private fun apps(vararg lines: String) = (listOf("\t\t\t\t\"apps\"", "\t\t\t\t{") + lines + "\t\t\t\t}").joinToString("\n")
private val sparking = arrayOf(
"\t\t\t\t\t\"1790600\"", "\t\t\t\t\t{", "\t\t\t\t\t\t\"LastPlayed\"\t\t\"1761897600\"", "\t\t\t\t\t\t\"LaunchOptions\"\t\t\"-dx11\"", "\t\t\t\t\t}",
)
@Test fun replacesTheOptionsSteamHas() {
val text = config(apps(*sparking))
val updated = SteamLaunchOptions.withLaunchOptions(text, 1790600, "-dx12")!!
assertEquals(text.replace("\"-dx11\"", "\"-dx12\""), updated)
assertEquals("-dx12", SteamLaunchOptions.launchOptions(updated, 1790600))
}
@Test fun addsOptionsToAGameThatHasNone() {
val text = config(apps("\t\t\t\t\t\"1790600\"", "\t\t\t\t\t{", "\t\t\t\t\t\t\"LastPlayed\"\t\t\"1761897600\"", "\t\t\t\t\t}"))
assertEquals(config(apps(*sparking)).replace("-dx11", "-vulkan"), SteamLaunchOptions.withLaunchOptions(text, 1790600, "-vulkan"))
}
@Test fun addsTheGameAndTheAppsSectionWhenSteamHasNeither() {
val updated = SteamLaunchOptions.withLaunchOptions(config("\t\t\t\t\"language\"\t\t\"english\""), 1790600, "-dx11")!!
assertEquals(
config(
"\t\t\t\t\"language\"\t\t\"english\"\n" +
apps("\t\t\t\t\t\"1790600\"", "\t\t\t\t\t{", "\t\t\t\t\t\t\"LaunchOptions\"\t\t\"-dx11\"", "\t\t\t\t\t}"),
),
updated,
)
assertEquals("-dx11", SteamLaunchOptions.launchOptions(updated, 1790600))
}
@Test fun quotesAndBackslashesAreEscapedAndReadBack() {
val options = "PROTON_LOG=1 %command% -path \"C:\\Games\\DB\""
val updated = SteamLaunchOptions.withLaunchOptions(config(apps(*sparking)), 1790600, options)!!
assertEquals(true, updated.contains("\"PROTON_LOG=1 %command% -path \\\"C:\\\\Games\\\\DB\\\"\""))
assertEquals(options, SteamLaunchOptions.launchOptions(updated, 1790600))
}
@Test fun emptyOptionsClearSteams() {
val updated = SteamLaunchOptions.withLaunchOptions(config(apps(*sparking)), 1790600, "")!!
assertEquals("", SteamLaunchOptions.launchOptions(updated, 1790600))
}
@Test fun windowsLineEndsAreKept() {
val text = config("\t\t\t\t\"language\"\t\t\"english\"").replace("\n", "\r\n")
val updated = SteamLaunchOptions.withLaunchOptions(text, 1790600, "-dx11")!!
assertEquals(false, updated.replace("\r\n", "").contains('\n'))
assertEquals("-dx11", SteamLaunchOptions.launchOptions(updated, 1790600))
}
@Test fun onlyTheGamesOwnSectionChanges() {
val other = arrayOf(
"\t\t\t\t\t\"7\"", "\t\t\t\t\t{", "\t\t\t\t\t\t\"1790600\"", "\t\t\t\t\t\t{", "\t\t\t\t\t\t\t\"LaunchOptions\"\t\t\"keep\"", "\t\t\t\t\t\t}", "\t\t\t\t\t}",
)
val updated = SteamLaunchOptions.withLaunchOptions(config(apps(*other, *sparking)), 1790600, "-dx12")!!
assertEquals(true, updated.contains("\"keep\""))
assertEquals("-dx12", SteamLaunchOptions.launchOptions(updated, 1790600))
assertNull(SteamLaunchOptions.launchOptions(config(apps(*other)), 1790600))
}
@Test fun otherFilesAreLeftAlone() {
assertNull(SteamLaunchOptions.withLaunchOptions("\"InstallConfigStore\"\n{\n}\n", 1790600, "-dx11"))
assertNull(SteamLaunchOptions.withLaunchOptions("", 1790600, "-dx11"))
assertNull(SteamLaunchOptions.launchOptions("", 1790600))
}
private fun steamHome(home: File = tmp.newFolder("Steam")): File = home.also {
File(home, "config").mkdirs()
File(home, "config/loginusers.vdf").writeText(
"\"users\"\n{\n\t\"76561198021239924\"\n\t{\n\t\t\"AccountName\"\t\t\"a\"\n\t\t\"MostRecent\"\t\t\"1\"\n\t}\n}\n")
}
private fun localConfig(home: File, account: String) = File(home, "userdata/$account/config/localconfig.vdf").apply { parentFile!!.mkdirs() }
@Test fun aChangeGoesToTheSignedInAccountOnly() {
val home = steamHome()
val signedIn = localConfig(home, "60974196").apply { writeText(config(apps(*sparking))) }
val other = localConfig(home, "123").apply { writeText(config("\t\t\t\t\"language\"\t\t\"english\"")) }
val untouched = other.readText()
assertTrue(SteamLaunchOptions.write(home, 1790600, "-dx12"))
assertEquals("-dx12", SteamLaunchOptions.launchOptions(signedIn.readText(), 1790600))
assertEquals(untouched, other.readText())
assertFalse(File(signedIn.parentFile, "localconfig.vdf.staged").exists())
}
@Test fun whatSteamWroteLastIsWhatTheGameHas() {
val home = steamHome()
val config = localConfig(home, "60974196").apply { writeText(config(apps(*sparking))) }
assertTrue(SteamLaunchOptions.write(home, 1790600, "-dx12"))
config.writeText(SteamLaunchOptions.withLaunchOptions(config.readText(), 1790600, "-vulkan")!!)
assertEquals("-vulkan", SteamLaunchOptions.steam(home, 1790600))
assertNull(SteamLaunchOptions.steam(home, 400))
}
private val app get() = RuntimeEnvironment.getApplication()
private val written = ArrayList<File>()
private fun sessionConfig(): File {
val home = steamHome(SessionPrefs.activeSteamRoot(app))
return localConfig(home, "60974196").apply { writeText(config(apps(*sparking))) }
.also { written += it; written += File(home, "config/loginusers.vdf") }
}
@After fun noSession() {
SessionState.running = false
SessionState.mode = SessionService.MODE_STEAM
written.forEach { it.delete() }
}
@Test fun aValueChangedInSteamSinceItWasShownIsNotOverwritten() {
val config = sessionConfig()
assertEquals(SteamLaunchOptions.Saved.NO, SteamLaunchOptions.set(app, 1790600, "-dx12", shown = "-vulkan"))
assertEquals("-dx11", SteamLaunchOptions.launchOptions(config.readText(), 1790600))
assertEquals(SteamLaunchOptions.Saved.YES, SteamLaunchOptions.set(app, 1790600, "-dx12", shown = "-dx11"))
assertEquals("-dx12", SteamLaunchOptions.launchOptions(config.readText(), 1790600))
}
@Test fun aDesktopSessionLeavesTheFileToItsClient() {
val config = sessionConfig()
val before = config.readText()
SessionState.running = true
SessionState.mode = SessionService.MODE_DESKTOP
assertEquals(SteamLaunchOptions.Saved.DESKTOP, SteamLaunchOptions.set(app, 1790600, "-dx12", shown = "-dx11"))
assertEquals(before, config.readText())
}
@Test fun nothingIsWrittenWithoutASignedInAccountsConfig() {
assertFalse(SteamLaunchOptions.write(tmp.newFolder("NoSteam"), 1790600, "-dx11"))
val home = steamHome()
assertFalse(SteamLaunchOptions.write(home, 1790600, "-dx11"))
localConfig(home, "60974196").writeText("\"InstallConfigStore\"\n{\n}\n")
assertFalse(SteamLaunchOptions.write(home, 1790600, "-dx11"))
}
}