Compatibility test: beta branch selector + launch options × Max's steam-features#3
Closed
Leb-Sun wants to merge 35 commits into
Closed
Compatibility test: beta branch selector + launch options × Max's steam-features#3Leb-Sun wants to merge 35 commits into
Leb-Sun wants to merge 35 commits into
Conversation
…oin game Steam Friends: - Right swipe-out drawer (Compose M3) mirroring the left drawer, with self status header, avatars, and In-Game/Online/Offline grouping. - Live friend presence: logon sends protocol_version, ChangeStatus with persona_set_by_user/need_persona_response, and subscribes via Chat.RequestFriendPersonaStates so Steam pushes stateful persona updates. - Wire-type-aware CMsgClientPersonaState parser (field 25 arrives as a fixed64 in stateful pushes); has_persona_state/has_game guards keep metadata-only responses from clobbering live state, game name, and app id. - In-game friends show a compact card with a text-height game-art capsule and the resolved game title beside it (title from the local app DB, then the public store API, since Steam omits game_name for Steam apps). - The redundant self-status section was removed from the left filter drawer. Steam Messages: - FriendMessages protobufs (SendMessage, GetRecentMessages, IncomingMessage) plus JNI for send, history, and a drainable incoming queue fed by the FriendMessagesClient.IncomingMessage notification. - Compose M3 chat screen with history, real-time incoming, optimistic send dedup, and avatars. - Image attachments: system photo picker -> Steam chat UGC upload (beginfileupload/PUT/commitfileupload with a minted web access token, file_type=MIME) delivered to the friend. Renders [img], [img src=...], and bare images.steamusercontent.com/ugc image URLs. Steam Achievements: - Trophy button on the game launch screen between Settings and Create Shortcut, opening a Compose M3 achievements screen with icons, names, descriptions, X/Y progress, and unlock dates. - Overlay the user's real unlock state from CMsgClientGetUserStatsResponse achievement blocks onto the schema-derived definitions. Join Game: - Join button on joinable in-game friends launches their game (when owned and installed) with the connect string appended to the Steam launch args (ColdClient ExeCommandLine and the Goldberg arg path). Launch options: - Steam-style %command% launch options: KEY=VALUE tokens before %command% become environment variables for the game process; arguments after %command% are passed to the game. Added a "Steam (%command%)" preset. Localization: - All new user-facing strings extracted to resources and translated across all 15 supported locales (da, de, es, fr, hi, it, ko, pl, pt-BR, ro, ru, uk, zh-CN, zh-TW, plus English).
…oin game Steam Friends: - Right swipe-out drawer (Compose M3) mirroring the left drawer, with self status header, avatars, and In-Game/Online/Offline grouping. - Live friend presence: logon sends protocol_version, ChangeStatus with persona_set_by_user/need_persona_response, and subscribes via Chat.RequestFriendPersonaStates so Steam pushes stateful persona updates. - Wire-type-aware CMsgClientPersonaState parser (field 25 arrives as a fixed64 in stateful pushes); has_persona_state/has_game guards keep metadata-only responses from clobbering live state, game name, and app id. - In-game friends show a compact card with a text-height game-art capsule and the resolved game title beside it (title from the local app DB, then the public store API, since Steam omits game_name for Steam apps). - The redundant self-status section was removed from the left filter drawer. Steam Messages: - FriendMessages protobufs (SendMessage, GetRecentMessages, IncomingMessage) plus JNI for send, history, and a drainable incoming queue fed by the FriendMessagesClient.IncomingMessage notification. - Compose M3 chat screen with history, real-time incoming, optimistic send dedup, and avatars. - Image attachments: system photo picker -> Steam chat UGC upload (beginfileupload/PUT/commitfileupload with a minted web access token, file_type=MIME) delivered to the friend. Renders [img], [img src=...], and bare images.steamusercontent.com/ugc image URLs. Steam Achievements: - Trophy button on the game launch screen between Settings and Create Shortcut, opening a Compose M3 achievements screen with icons, names, descriptions, X/Y progress, and unlock dates. - Overlay the user's real unlock state from CMsgClientGetUserStatsResponse achievement blocks onto the schema-derived definitions. Join Game: - Join button on joinable in-game friends launches their game (when owned and installed) with the connect string appended to the Steam launch args (ColdClient ExeCommandLine and the Goldberg arg path). Launch options: - Steam-style %command% launch options: KEY=VALUE tokens before %command% become environment variables for the game process; arguments after %command% are passed to the game. Added a "Steam (%command%)" preset. Localization: - All new user-facing strings extracted to resources and translated across all 15 supported locales (da, de, es, fr, hi, it, ko, pl, pt-BR, ro, ru, uk, zh-CN, zh-TW, plus English).
Settings gear in the friends drawer self-status row opens a Chat Settings dialog: Chat Notifications, Chat Heads, Auto-Hide, and Enable Chat in Game. - Global incoming-message pipeline in SteamService: a single poller drains messages and re-publishes via a SharedFlow plus per-friend unread counts, consumed by the chat screen, system notifications, and the chat-head overlay. - System notifications (high-importance channel) for incoming friend messages. - Messenger-style chat heads: a draggable system-overlay bubble that snaps to any screen edge, fades when idle (Auto-Hide), shows an unread badge, and un-hides on a new message; tapping pops a panel beside the head with the full friends list (game-art badges) and a conversation view (text + image send via a transparent picker proxy). Works over games when Enable Chat in Game is on. - In-game gating via GameSessionState; orientation-aware re-snapping.
Adds a "Launch Options" item to the STEAM menu on the game detail screen that lists the game's appinfo config.launch entries (e.g. ARK's "Launch ARK (No BattlEye)") with a checkmark on the current choice. Selecting one persists as the game's default: - exe -> shortcut extra launch_exe_path + container.executablePath (the priority resolveRelativeGameExe already honors; non-default exes ride the existing WN_STEAM_DIRECT_EXE override) - the option's own arguments -> new shortcut extra launch_exe_args, kept separate from the user's custom execArgs LaunchInfo gains an `arguments` field (defaulted, so cached appinfo JSON stays decodable) parsed from appinfo config/launch/arguments. A shared SteamUtils.combineSteamLaunchArgs joins option args with custom args across all three launch channels (direct command line, ColdClientLoader.ini ExeCommandLine, localconfig.vdf LaunchOptions / GetLaunchCommandLine). It honors Steam's %command% placeholder in custom args. The steam-env warm stamp now includes the effective LaunchOptions line so a changed selection re-runs the localconfig edit, and warm launches re-push the per-process launch command line. The submenu reuses the existing StoreSourceActionPopup surface and StoreSourceMenuItem styling; hidden unless the game is installed and has 2+ distinct options. https://claude.ai/code/session_01EUsZxzAWCjSh8LYRS9W3vT
The v1 selector only existed on the store detail screen (StoreGameDetailScreen); tapping an installed game in the library grid opens LibraryGameDetailDialog -> LibraryGameLaunchScreen, which has its own duplicated STEAM dropdown - so the feature was invisible from the library. Mirror the submenu there (same two-page popup, using this screen's Launch* styling) and wire it in LibraryGameDetailDialog for Steam games only. Also fix two latent issues that could hide or weaken the selector: - Cached appinfo rows predate LaunchInfo.arguments, so options that differ only by args deduped down to one entry and fell under the 2-option visibility gate. Dedup now includes the option label, and both dialogs do a two-phase load: show cached options immediately, then SteamService.refreshAppInfoFromPics (new public wrapper around fetchLatestSteamAppInfo + persistLatestSteamAppInfo) re-fetches the app's PICS appinfo and reloads, healing upgraded installs on first open. - Extracted the option-list builder and selection persistence into shared UnifiedActivity helpers used by both screens, replacing GameManagerDialog's inline copies. https://claude.ai/code/session_01EUsZxzAWCjSh8LYRS9W3vT
The in-popup submenu rendered as an awkward full-width overlay. Replace it with a centered modal window that follows the Workshop window's design language: dimmed scrim, 560dp-max rounded Surface, header with an accent icon badge + LAUNCH OPTIONS overline + game title + count chip + close button, and a divided row list. Rows show the option label with its executable/arguments as the secondary line; tapping persists the selection and moves the check mark. - New LaunchOptionsScreen.kt mirroring WorkshopScreen's palette and layout (all vector icons; no new drawable assets needed). - Both STEAM dropdowns return to a flat menu whose "Launch Options" item opens the window (showLaunchOptions/onLaunchOptions params replace the list plumbing through the SourceTags). - LaunchOptionsDialog host added next to WorkshopDialog in both GameManagerDialog and LibraryGameDetailDialog. https://claude.ai/code/session_01EUsZxzAWCjSh8LYRS9W3vT
Findings from a full-branch review applied: - PICS appinfo re-fetch now runs once per app per process (retried on failure) instead of on every game-detail open, and the two-phase load + refresh logic is shared by both dialogs via loadSteamLaunchOptionsRefreshing — drops a network round-trip and a duplicate shortcut scan from repeat opens. - LaunchOptionsDialog owns selection persistence (appId + onSelectionSaved), removing the duplicated persist lambda from both host sites. - XServerDisplayActivity: single combineWithSelectedLaunchArgs resolver replaces the getExtra+combine pattern repeated across the direct-launch and both ColdClient INI sites. - Steam-env stamp stores the raw effective LaunchOptions line instead of its hashCode — exact equality, no silent collision skips. - StoreLaunchOptionItem moved to LaunchOptionsScreen.kt where the picker lives. https://claude.ai/code/session_01EUsZxzAWCjSh8LYRS9W3vT
Adds a "Beta Branch" menu item to the STEAM ▾ dropdown on both game detail screens (StoreGameDetailScreen / LibraryGameLaunchScreen). Tapping it opens a Workshop-styled picker (BetaBranchScreen.kt) listing the game's PICS branches with the current one check-marked. Password-protected branches are shown disabled (no beta-password flow exists in this app). • BetaBranchScreen.kt — new Workshop-shaped modal; mirrors the structure of LaunchOptionsScreen.kt with AltRoute icon and per-file palette constants. • Menu item hidden when the game has only one branch (public), mirroring the >= 2 gate used by Launch Options. • Persistence: SteamService.setSelectedBetaBranch() stores the choice as the "selectedBranch" shortcut extra (blank = public/default); SteamService.resolveSelectedBetaName() refactored to reuse findSteamShortcut() instead of its own loadShortcuts() scan. • Downstream already honors the selection (resolveDepotManifestInfo, setAppCurrentBeta, ACF buildId); after a successful save the dialog calls startUpdateCheck() so the new branch's build downloads. • SteamUtils.writeCompleteSettingsDir: configs.app.ini [app::general] now writes is_beta_branch/branch_name from the actual selected branch instead of always hardcoding public, so gbe_fork's GetCurrentBetaName() / GetAppBuildId() return correct values. branches.json already lists all branches correctly — no change needed. • Appinfo refresh guard generalised: launchOptionsRefreshedApps renamed to appinfoRefreshedApps so one PICS round-trip per process feeds both the Launch Options and Beta Branch pickers. https://claude.ai/code/session_01EJFSZYUPkR1Cwer6CC2cNa
startUpdateCheck was calling checkForAppUpdate(appId) without a branch, so the comparison always ran against the public manifests and reported "no updates found" even after switching branches. The private downloadApp overload (routing downloadAppForUpdate) also hardcoded branch = "public", so the download itself would have fetched the wrong manifests even if the check had passed. Fix: resolve resolveSelectedBetaName before the update check and pass it to checkForAppUpdate; resolve it again inside the private downloadApp overload instead of hardcoding "public". Fresh installs (no shortcut yet) resolve to "" → "public" unchanged. https://claude.ai/code/session_01EJFSZYUPkR1Cwer6CC2cNa
…ownload hot paths
Clicking install/check-update crashed after the branch-selector fix:
resolveSelectedBetaName ran ContainerManager().loadShortcuts(), whose
Shortcut constructor decodes full cover-art bitmaps for every shortcut,
runs PE icon extraction over game exes and can rewrite .desktop files.
Doing that on every download/update click spikes the heap (OOM lands on
whatever thread allocates next — runCatching can't save the app) and
races the UI's own .desktop reads.
resolveSelectedBetaName now parses the [Extra Data] section of the
.desktop files directly — no Shortcut construction, no bitmap decode,
no writes. The heavyweight findSteamShortcut path remains only in the
one-off setter (setSelectedBetaBranch).
Also:
• checkForAppUpdate / isUpdatePending default their branch parameter to
the game's selected beta, so every caller (startUpdateCheck, the
store dialog's onDownloadUpdate) is branch-aware without per-site
resolution; the UnifiedActivity call site is back to one line.
• startUpdateCheck wraps downloadAppForUpdate in runCatching — a failed
update start now shows the failure popup instead of crashing.
• completeAppDownload prunes stale "{depotId}_{gid}.manifest" caches
not matching depot.config — branch switches no longer accumulate old
manifests, and checkForAppUpdate's cache fallback can't mistake a
previously-downloaded branch for the installed one. Legacy installs
without depot.config are left untouched.
• BetaBranchScreen: remember() the formatted date; ktlint-safe wrapping.
Known limitation (documented, native-side): the Rust depot writer does
not delete game files absent from the new branch's manifest, so files
removed between branches linger until a fresh install. Fixing that needs
a manifest-diff pass in wn-steam-client.
https://claude.ai/code/session_01EJFSZYUPkR1Cwer6CC2cNa
Applied from a seven-angle review pass (line-scan, removed-behavior, cross-file tracing, reuse, simplification, efficiency, altitude): • "public" comparisons now case-insensitive (equals ignoreCase), matching the existing convention in branches.json / manifest resolution — covers the row label, sort order, selection fallback, blank-mapping on save, and configs.app.ini is_beta_branch. • Branch picker closes after a successful save so the update-check popup it triggers is what the user sees next, not a stale window. • Install/DLC size estimates in GameManagerDialog are sized against the selected branch (resolved once per load) — previously the cards showed public-branch sizes while the download fetched the beta. • readSelectedBranchExtra uses FileUtils.readLines (same reader as Shortcut's parser): one corrupt .desktop file no longer aborts the scan of remaining containers. • Stale-manifest prune extracted to pruneStaleDepotManifestCache next to the other cleanup helpers. • Store onInstall download start wrapped in runCatching — an exception there killed the app (plain coroutine launch, no handler). • Dropped the redundant pwdRequired guard in the picker row callback; the row-level clickable gate already enforces it. https://claude.ai/code/session_01EJFSZYUPkR1Cwer6CC2cNa
getSelectedLaunchOption ran ContainerManager().loadShortcuts() on every game-detail open. Each Shortcut constructed that way decodes the full cover-art bitmap, runs PE icon extraction over the game exe and can rewrite .desktop files — a large transient heap spike and a write race against the UI's own shortcut reads, just to fetch two strings. New readSteamShortcutExtras parses the [Extra Data] section straight from the .desktop files and returns the owning container dir; the container.executablePath fallback is read from the .container config JSON directly. The heavyweight findSteamShortcut path remains only in setSelectedLaunchOption, which must materialize the shortcut to write. https://claude.ai/code/session_01EJFSZYUPkR1Cwer6CC2cNa
The Steam store tab crashed on game tap while the library detail worked. GameManagerDialog runs three data-loading LaunchedEffects the library dialog doesn't all share — and an exception inside a LaunchedEffect tears down the whole Activity. All data-loading effects in GameManagerDialog and the shared launch-options/beta-branches loader effects now degrade on failure (logged, menu items hidden / zero sizes) instead of crashing, with CancellationException rethrown so effect restarts still work. Also dedupes the merged shortcut readers: resolveSelectedBetaName now uses readSteamShortcutExtras from the launch-options branch (which gained the same lightweight .desktop reader for getSelectedLaunchOption) and the selectedBranch-specific copy is gone. Read and write paths now agree on "first STEAM shortcut for the appId". https://claude.ai/code/session_01EJFSZYUPkR1Cwer6CC2cNa
…een signature
The store-tab crash was never a logic bug: ART's bytecode verifier
rejected StoreGameDetailScreenKt itself —
VerifyError: [0x17BC] wide register v5 has type Low-half
Constant/Zero/null
a D8/Compose codegen defect triggered by the composable's huge
parameter list (≈44 params incl. several longs + default masks). The
launch-options build, two parameters smaller, verified fine on the
same device; adding showBetaBranches/onBetaBranches pushed the
generated default-argument handler over the edge. The class failed to
load the moment the store dialog composed it — which is why it crashed
instantly, for every game, store tab only, and no runCatching could
help.
Fix: fold each show-flag + callback pair into a single nullable
callback (null = menu item hidden) in StoreGameDetailScreen,
LibraryGameLaunchScreen and their source-tag menus. That returns
StoreGameDetailScreen to exactly the parameter count that demonstrably
passes the verifier, with a slightly cleaner API.
Also fixes the PR CI compile failure: the merge had interleaved a
duplicate com.winlator.cmod.shared.io.FileUtils import in
SteamService.kt ("Conflicting import: name is ambiguous").
https://claude.ai/code/session_01EJFSZYUPkR1Cwer6CC2cNa
…rifier Second VerifyError from the same device, different instruction: [0x1749] copy-cat1 v0<-v260 type=Reference: WindowInsets v260 is the tell: with the 40+-param defaulted signature and the whole screen body compiled into one method, the frame needed 260+ registers, and at that pressure D8's prologue emits register copies this device's ART verifier rejects. Reshaping parameters (previous commit) just moved the failure — the giant shared frame is the trigger. Fix splits the two pressure sources into separate methods: • StoreGameDetailScreen keeps the exact public defaulted signature but its body is now only "pack args into StoreGameDetailParams, call content" — a small frame containing the default-mask prologue. • StoreGameDetailContent(p) holds the original body behind local rebinds (body text unchanged) — a big body but a one-param method with no default machinery, so the frame stays well under the high-register regime. Call sites are untouched; behavior is identical. https://claude.ai/code/session_01EJFSZYUPkR1Cwer6CC2cNa
Debloat from the crash investigation, now that the real cause (VerifyError, fixed by the wrapper/content split) is known: • Reverted the speculative runCatching guards added while hunting blind — GameManagerDialog's install-data load, the DLC size effect and the onInstall download call are back to the unguarded house style they had on main. Kept the two intentional guards: the launch-options/beta loader effects (network-dependent PICS refresh; failure should hide menu items, not kill the dialog) and startUpdateCheck's downloadAppForUpdate (our feature's primary flow). • Extracted refreshAppInfoFromPicsOnce — the once-per-process PICS refresh guard previously duplicated inside both loader functions. • Trimmed stale verifier-saga comments from the nullable menu-callback params; the full story lives once, on StoreGameDetailParams where the split it explains actually is. https://claude.ai/code/session_01EJFSZYUPkR1Cwer6CC2cNa
…innative-fork-steam-merge-sbh1lx
…ility testing Combines the Steam beta-branch selector + launch-options selector (PRs #1/#2) with Max's steam-features branch (friends/presence drawer, chat, achievements, game joining, Steam-style launch option syntax), on top of upstream main 830008b. Conflicts resolved in XServerDisplayActivity.java (3 hunks, all in the Steam launch-args pipeline): both sides are now chained as appendSteamJoinConnect(SteamLaunchOptions.gameArgs(combineWithSelectedLaunchArgs(execArgs))) so the per-game selected launch option's args are merged into the custom args first (preserving %command% placement), then Max's parser strips the env-var prefix and extracts game args, then a friend-join connect string is appended. Env-var extraction (parseEnvVars) still reads the raw execArgs, which is unaffected by the combine step. https://claude.ai/code/session_0122eiViExS97baaDytDSYJq
Pre-install, the store screen's Download pill now has a small segment "sliced off" its left edge (AltRoute icon, 48dp — min touch target, mirrored 14dp/4dp corners with the house 8dp gap) that opens the existing beta-branch picker. The pick is STAGED in memory only (pendingBetaBranch); size cards retarget to the staged branch immediately, and nothing persists or downloads until the Download button commits it. • StoreCtaButton gains defaulted modifier/shape params; the glass brushes are extracted into storeCtaGlassBrushes shared with the new StoreCtaCutoutButton. Zero new StoreGameDetailScreen params — the existing nullable onBetaBranches drives the cutout pre-install and the STEAM-menu item post-install, so Epic/GOG (null) never show it. • GameManagerDialog loads beta branches for both install states (after the install state resolves, so the cutout can't flash on installed games); launch options stay install-gated. • BetaBranchesDialog is now a dumb shell with a single onSelect — the installed hosts (GameManager + library) persist and start the update check exactly as before; the pre-install host just stages and closes. • Download commit: persists a custom install path BEFORE the branch write (setSelectedBetaBranch creates the shortcut, which snapshots game_install_path and is never rewritten — committing in the other order would freeze the default path and break launch from custom dirs), then downloads; pause/resume re-resolves the branch from the now-persisted shortcut. If the shortcut can't be created yet (setup incomplete) the install proceeds on public with the existing beta-branch-failed toast. https://claude.ai/code/session_01EJFSZYUPkR1Cwer6CC2cNa
Reinstalling WinNative wipes app-private shortcuts (where the selectedBranch extra lives) while game files on external storage survive — so a reinstalled app showed a beta install as "public", and worse, a tapped update check would diff the beta files against public manifests and silently downgrade the game. Steam survives this because it persists the beta key WITH the install (appmanifest ACF, UserConfig/betakey). Our durable analogs live in the surviving game dir, used in order of trust by the new recoverSelectedBetaName(appId): 1. .DepotDownloader/depot.config — the installed manifest gids matched exactly against each beta's PICS manifests (evidence of what the files actually are; requires all overlapping depots to match and at least one gid to differ from public, single candidate only); 2. steam_settings/configs.app.ini branch_name — the selection recorded at the game's last launch (checked at the game-dir root and next to the exe, the two settings-dir locations the launch path writes). A successful inference heals the shortcut via setSelectedBetaBranch, so every downstream consumer is consistent again. Wired at the three chokepoints: the branch-picker loader (UI), checkForAppUpdate / isUpdatePending (branch param now nullable, null = recover-and-resolve) and prepareLibSteamClientForLaunch (game launch). Known limitation: a never-launched install whose beta has since published a new build matches neither source and stays public until re-picked. https://claude.ai/code/session_01EJFSZYUPkR1Cwer6CC2cNa
…ecovery From a seven-angle review of the two newest commits: • Branch-name casing: an ini-recovered name is now canonicalized to the PICS branches-map key before healing — downstream buildId lookups (app.branches[name]) are exact-key and would silently miss an ini-cased variant. • Recovery is memoized per process (betaRecoveryAttemptedApps): it can only succeed right after a WinNative reinstall, so permanently-public games no longer rerun the full inference (DB read + depot.config parse + ini probes) on every dialog open, update check and launch. • readBranchNameFromSettingsIni derives the exe dir from the SteamApp already in hand instead of getWindowsLaunchInfos' redundant blocking DB fetch of the same row. • pendingBetaBranch is cleared when a game resolves to installed — a staged pre-install pick was either committed by Download or abandoned, and could otherwise leak into a later session of the dialog. The host's selectedBranch expression simplifies to pending ?: persisted on that invariant. • The branch cutout now shares the Download button's enabled gate so users can't stage picks an actively-blocked download won't honor. • The 20-line commit block in onInstall is extracted to commitPendingBetaBranch, mirroring the persist helper next to it. Refuted during verification, for the record: cutout-without-betas (the host gates onBetaBranches on branches.size >= 2), cross-game state leaks (remember(app.id) keying), setSelectedBetaBranch false-success (it returns false on a null shortcut), customPath double-application (idempotent by construction), and the lost explicit-public API (callers can pass requestedBranch = "public"). https://claude.ai/code/session_01EJFSZYUPkR1Cwer6CC2cNa
The beta-branch cutout and the Download segment each painted the full teal->purple gradient, so it repeated. Each segment now paints only its slice of a single gradient spanning the whole row, matching the look of the undivided Download button. https://claude.ai/code/session_013E3pTpGg4C6ropUPA9QyNB
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Purpose
CI compatibility check before opening the individual feature PRs. This branch merges, on top of upstream main (
830008b, synced today):claude/steam-beta-branch-selector-ckipz0(PRs feat(steam): Launch Options selector in the STEAM dropdown #1 + feat(steam): beta branch selector in the STEAM dropdown #2 — my Steam launch options + beta branch work)maxjivi05:steam-features(Max's Steam social features)Not intended to be merged — this exists to trigger a CI build and prove the two feature sets coexist.
My features (PRs #1 / #2)
config.launchentries (e.g. ARK's "No BattlEye"). Selection persists as shortcut extras (launch_exe_path/launch_exe_args);SteamUtils.combineSteamLaunchArgsmerges the option's args with custom args across all three launch channels, honoring%command%.steam_settingswriter now reports the active branch to gbe_fork.Max's features (steam-features)
KEY=VALUEtokens before%command%become env vars (SteamLaunchOptions.parseEnvVars), args after become game args (SteamLaunchOptions.gameArgs).Merge conflict resolutions
Only one file conflicted:
XServerDisplayActivity.java— three hunks, all the same overlap in the Steam launch-arguments pipeline (direct command line + the two ColdClientLoader.ini writers). My side wrapped exec args withcombineWithSelectedLaunchArgs(...); Max's side wrapped them withappendSteamJoinConnect(SteamLaunchOptions.gameArgs(...)).Resolution — chain the two pipelines, preserving both behaviors:
combineWithSelectedLaunchArgsmerges the selected launch option's args into the custom args first, keeping them attached to%command%(e.g.FOO=1 %command% -windowed+ selected-NoBattlEye→FOO=1 %command% -NoBattlEye -windowed).SteamLaunchOptions.gameArgsthen strips the env-var prefix and extracts the game args (-NoBattlEye -windowed).appendSteamJoinConnectappends the friend-join connect string when launching via a join.Env-var extraction (
parseEnvVars, line ~5567) still reads the raw execArgs and is unaffected, since the combine step only inserts after%command%. The localconfig.vdf / warm-stamp channel was touched only by my branch and merged untouched.Semantic checks done on auto-merged files: both features' menu items/dialogs intact in
UnifiedActivity.kt,StoreGameDetailScreen.kt,LibraryGameLaunchScreen.kt; no duplicate string resources or symbols; no references to code removed by the upstream sync; no leftover conflict markers.Test plan
KEY=VALUE %command%syntax still sets env varshttps://claude.ai/code/session_0122eiViExS97baaDytDSYJq
Generated by Claude Code